Как правильно объявить сам ссылающийся тип шаблона? - PullRequest
5 голосов
/ 02 июня 2011

Как мне объявить шаблонный тип, который ссылается на себя?

template <class T = Animal> class Animal
{
public:
    T getChild ();
}

При этом я получаю ошибку компилятора, касающуюся отсутствующего спецификатора типа.Я попытался переадресовать Animal, но безуспешно.

Я пытаюсь наложить ограничение типа.Lion может иметь только Lion в качестве ребенка, Bear имеет Bear и т. Д.

РЕДАКТИРОВАТЬ

I 'Я опубликую часть фактического класса.Это шаблон для классов, которые могут появляться в связанном списке:

template <class T = Linked<T> > class Linked
{
private:
    T* m_prev;
    T* m_next;
}

Я хочу обеспечить, чтобы класс мог указывать только на объект того же класса (или подкласса).

Ответы [ 4 ]

4 голосов
/ 02 июня 2011

На ФП ответили, но я хочу вмешаться, потому что непосредственной причиной проблемы является не рекурсия, как утверждают другие. Самая простая причина, по которой это не сработает, заключается в том, что шаблоны классов не типов. Это шаблоны. Точно так же шаблоны функций также не являются функциями. Так что все это бессмысленно:

template<typename T> int function_template(int);
typedef int function_type(int);
void eats_a_function(function_type&); // needs a reference to function

std::vector< std::vector > vec0; // std::vector is not a type
std::vector< std::list > vec1; // std::list is not a type
eats_a_function(function_template); // function_template is not a function

Обратите внимание, что в случае vec1, std::list не связано с std::vector. Шаблон полностью определен (при условии включения заголовка) в момент его создания. Это все еще не будет работать.

Вместо этого работает следующее:

std::vector< std::vector<int> > vec2; // std::vector<int> is a type
std::vector< std::list<double> > vec3; // std::list<double> is a type
eats_a_function(function_template<long>); // function_template<long> is a function

Обратите внимание, что в случае с vec2 нормально передать экземпляр самого шаблона.


Для справки, игрушечное решение проблемы с игрушкой при написании шаблона, который ссылается на себя, используя пресловутый слой косвенности:

// expects a template that expects a type
template<template<class> class T> struct indirection {};

// forward decl. for defaulting the parameter
template<typename T> struct recursive;

// template that expects a type
template<typename T = indirection<recursive> > struct recursive {};

Не очень мощный, учитывая несколько вещей, которые возможны с шаблоном (параметр T внутри indirection). Конечно, можно написать метафункцию в стиле rebind, которая возвращает экземпляр T.

4 голосов
/ 02 июня 2011

В этом случае вам нужно указать некоторый параметр типа для Animal в вашем определении typename, иначе это будет «бесконечная рекурсия» в конструкции типа:

template<class T> class Animal;//you'll need this forward declaration

template <class T = Animal<int> > class Animal //int is just an example
{
public:
    T getPrey ();
}
1 голос
/ 02 июня 2011

Обычный способ сделать что-то вроде связанного списка:

template <class T> class Linked
{
private:
    Linked<T>* m_prev;
    Linked<T>* m_next;
}

Это работает для вас, и если нет, то чего вы пытаетесь достичь, чего нельзя сделать таким образом?

1 голос
/ 02 июня 2011

Вы не можете создать класс шаблона, в котором типом шаблона является сам класс. Это логическая рекурсия, которую ваш компилятор не может смягчить. Поскольку для шаблонов требуется, чтобы компилятор создавал объект при обнаружении определенной типизации (скажем, Animal), необходимо иметь полное определение типа шаблона. В противном случае компилятор будет рекурсивно пытаться создавать объекты. Поскольку ваш объект ссылается на себя, это будет неразрывная рекурсия.

Этот вариант использования кажется гораздо более подходящим для наследования, чем для шаблонов.

Выполнение этого позволит вам скомпилировать: шаблон класса животных { общественности: T getPrey (); }

Или, если вы действительно не хотите использовать аргумент по умолчанию:

template <class T=Cheetah> class Animal
{
public:
    T getPrey ();
}

Тем не менее, гепард не должен использовать себя или животное в качестве одного из своих потенциальных типов шаблонов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...