Наличие шаблона указателя и указателя на функцию-член в качестве аргументов шаблона в C++03

Я хочу определить класс шаблона с двумя аргументами шаблона:

  1. Тип указателя T*
  2. Указатель на функцию-член базового типа T

Кроме того, я хотел бы установить метод по умолчанию для аргумента функции.

// Do not allow SortedLinkedList<T>
template<typename T, bool (T::* comparisonMethod)(const T&) = &T::lessEqual>
class SortedLinkedList
{
private:
    SortedLinkedList();
};

// Allow SortedLinkedList<T*>
template<typename T, bool (T::* comparisonMethod)(const T&)>
class SortedLinkedList<T*>
{
public:  
    void insert(T* item)
    {
        // do something with /item->*comparisonMethod)(...))
    }
};

Этот код не компилируется, потому что g++ (4.4.3) не может вывести базовый тип T*

error: creating pointer to member function of non-class type ‘T*’

Есть ли способ вывести базовый тип уже в объявлении класса? decltype недоступен в C++03, и я не знаю, будет ли он работать в этом месте.

Я нашел этот ответ, но он не помогает в этом кейс.

Спасибо


person ask4711    schedule 16.02.2015    source источник


Ответы (1)


Эта проблема

Причина, по которой он не компилируется, заключается в том, что компилятор проверит, что основной-шаблон является жизнеспособным соответствием, прежде чем он продолжит поиск специализация, которая является более подходящей альтернативой.

Это означает, что когда вы пытаетесь создать экземпляр SortedLinkedList<A*>, компилятор пытается проверить, правильно ли сформировано объявление bool (T::* comparisonMethod)(const T&) = &T::lessEqual в основном-шаблоне с T = A*, что, очевидно, не так (поскольку указатели могут не имеют функций-членов).


Решение

Один из способов решить эту проблему — добавить уровень косвенности, чтобы и первичный шаблон, и специализация давали корректную реализацию.

template<class T> struct remove_pointer     { typedef T type; };
template<class T> struct remove_pointer<T*> { typedef T type; };

<суп>

template<class T>
struct comparison_method_helper {
  typedef typename remove_pointer<T>::type Tx;
  typedef bool (Tx::*type)(Tx const&) const;
};

<суп>

// primary-template
template<
  class T,
  typename comparison_method_helper<T>::type = &remove_pointer<T>::type::lessEqual
> class SortedLinkedList;

// specialization
template<typename T, typename comparison_method_helper<T>::type func>
class SortedLinkedList<T*, func> {
  public:
    void insert (T const& item) {
      (item.*func) (T ());
    }
};

<суп>

#include <iostream>

struct A {
  bool lessEqual (A const&) const {
    std::cerr << "hello world\n";
    return false;
  }
};

int main () {
  SortedLinkedList<A*> ().insert (A()); // outputs 'hello world'
}
person Filip Roséen - refp    schedule 16.02.2015