Когда следует использовать ключевое слово "typename" при использовании шаблонов - PullRequest
3 голосов
/ 19 ноября 2010

В последнее время я работаю над небольшим проектом и не могу что-то выяснить ..

Мне дали файл .h, который содержал класс, используя шаблон typename. Внутри этого класса был частный класс.

template <typename T>
class Something
{
public:
        Something();
        ~Something();

        Node* Function1(int index);
        int Index(const T& id);


private:
        class Node()
        {
                public:
                T id;

                //Imagine the rest for the Node


        };      
};

Проблема возникла, когда я захотел определить функции класса «Что-то»

Вот как я это делал (в файле .inl)

template<typename T>
Node* Something::Function1(int index) //Is the return type well written?
{
        // returns the node at the specified index
}

template<typename T>
int Something::Index(const T& id) //Is the parameter type well specified?
{
        // returns the index of the node with the specified id
}

Таким образом, часть с ошибками была в части определений ... Должен ли я сказать компилятору, что тип возвращаемого значения (в данном случае Node *) использует шаблон typename (например: typename Node*)? А как насчет параметра? typename const Node&?

Таким образом, в основном, когда мне нужно указать, будет ли функция / параметр использовать шаблон?

Спасибо за ваше время.

Ответы [ 4 ]

5 голосов
/ 19 ноября 2010

Для Function1 вам нужно сообщить компилятору, что такое Node - в данном случае это вложенный тип внутри Something<T>. Поскольку он зависит от T (это зависимое имя), вы должны сообщить компилятору, что это тип, поэтому вы должны написать его как typename Something<T>::Node. Проблема в том, что могут быть некоторые T, для которых Something<T>::Node на самом деле не является типом (т. Е. Если вы частично специализируете Something<T>).

Для Index все, что у вас хорошо, const T& - это просто ссылка на const T, и компилятор знает, что такое T.

3 голосов
/ 19 ноября 2010

Простое правило: вам нужно использовать ключевое слово typename каждый раз, когда вы называете тип с использованием синтаксиса Class::Type, если часть Class зависит от параметра шаблона. (Часть Class может быть параметром шаблона или typedef в шаблоне класса и т. Д.)

Редактировать: Существует также некоторая путаница с правилами вложенных классов. Это в основном не зависит от проблемы typename, так что здесь не шаблонный пример.

class Outer {
public:
  class Inner {
  };
  Inner* func(Inner* obj);
};

Outer::Inner* func(Inner* obj)
{
}

Полное имя Inner равно Outer::Inner. Но вы также можете использовать более короткое имя Inner в любом месте области видимости класса Outer, включая все объявления func. При определении func тип возвращаемого значения НЕ находится в области действия Outer, поэтому необходимо полное имя. Но после ( параметры функции находятся в области действия Outer, поэтому короткое имя в порядке.

В сочетании с шаблонностью исходного примера, поскольку эквивалент Outer равен Something<T>, вам нужно ключевое слово typename, чтобы сказать Something<T>::Node.

2 голосов
/ 19 ноября 2010
template<typename T>
typename Something<T>::Node * Something::Function1(int index) //Is the return type well written?
{
        // returns the node at the specified index
}
1 голос
/ 19 ноября 2010

typename и class эквивалентны в списке параметров типа шаблона:

template <class T> class C;

совпадает с

template <typename T> class C;

Где требуется typename при обращении зависимые имена :

template <typename T> struct A {
    typedef typename T::some_type container;
};
...