Шаблон класса C ++ T проблема - PullRequest
1 голос
/ 22 февраля 2010
template <class T>
class List
{
    public:

        List();
        ~List();

        ...

    protected:

        template <class T> struct Item
        {
            struct Item* next;
            T data;
        };

        ...

        struct Item<T>* allocate();
};

template <class T>
struct Item<T>* List<T>::allocate() // error here
{
    ...
    return object; // struct Item<T>*
}

как я могу это сделать?

Ответы [ 5 ]

3 голосов
/ 22 февраля 2010

Вы повторно используете имя типа T. Используйте другой: template <class U> struct Item { ... (или удалить шаблонизацию из Item все вместе - похоже, у вас все в порядке с внешним параметром шаблона):

template <class T>
class List
{
    ...
    protected:

        struct Item
        {
            Item* next;
            T data;
        };

        Item* allocate() { return object; }
};
3 голосов
/ 22 февраля 2010

Правильный синтаксис для определения метода:

template <class T>
typename List<T>::Item* List<T>::allocate()
{ 
    ... 
    return object; // struct Item<T>* 
} 

По какой-то причине другие авторы настаивали на том, чтобы прикрепить деталь <T> к Item вместо List (обманутая вашей первоначальной версией, очевидно).

Извините, я не заметил, что Item также является соблазном. В этом случае это должно быть

template <class T> 
typename List<T>::template Item<T>* List<T>::allocate()
{ 
    ... 
    return object; // struct Item<T>* 
} 

Однако обратите внимание, что повторное использование одного и того же имени параметра во внутреннем объявлении шаблона запрещено! Ваше оригинальное определение класса недопустимо. Это должно быть изменено на что-то вроде

template <class T>
class List 
{ 
  ... 
  template <class U> struct Item // Note: `U` used intead of `T`
  { 
    struct Item* next; 
    U data; 
  }; 
  ...
  struct Item<T>* allocate(); 
}; 
2 голосов
/ 22 февраля 2010

Запись:

template <class T>
struct List<T>::Item* List<T>::allocate()
// etc

Оператор :: сообщает компилятору, что Item является вложенным классом List.

1 голос
/ 22 февраля 2010

Проблема на самом деле глубже:

Вам не нужно объявлять Item как template, потому что это вложенный класс в шаблонном классе, у которого есть доступ к T.

template <class T>
class List
{
public:

private:
  struct Item { ... };
};

И тогда вы бы определили access так:

template <class T>
typename List<T>::Item List<T>::access(...) {}

Дело в том, что List является классом шаблона, поэтому его параметры должны быть указаны, в то время как для List указано T, нет необходимости уточнять его еще раз.

Примечание typename;)

1 голос
/ 22 февраля 2010

Вам необходимо указать тип: List::Item<T>.

Вы можете использовать неквалифицированное имя типа, когда находитесь внутри объявления класса или внутри списка аргументов или тела каждой из функций-членов типа (или производных классов), но не для возвращаемого типа , Когда компилятор разрешает тип возвращаемого значения, он еще не знает, что вы определяете элемент шаблона List, и поэтому не будет заглядывать внутрь области этого класса.

Это интересный момент о том, как работают компиляторы, который фактически повлиял на некоторые изменения в будущем стандарте, позволяющие auto подобно определениям возвращаемого типа:

template<typename T, typename U>
auto sum( T lhs, U rhs ) -> delctype(lhs+rhs) 
{ return lhs+rhs; }

Компилятор может выводить типы T и U при наличии аргументов, но вы не можете сказать, что тип возвращаемого значения decltype(lhs+rhs) как тип возвращаемого значения, поскольку ни lhs, ни rhs пока нет в рамках. Хотя это проблема только C ++, она имеет корни в той же проблеме, с которой вы сталкиваетесь: область действия возвращаемого типа является внешней по сравнению с областью действия метода, который объявлен.

...