Почему вы не можете использовать шаблон при итерации - PullRequest
1 голос
/ 11 июля 2009

При компиляции:

#include <vector>

template<class T> class foo {

    void bar() {
        std::vector<T> x;
        std::vector<T>::iterator i = x.begin();

    }
};


int main() {
    return 0;
}

Я получаю:

# g++ ~test.cpp
test.cpp: In member function `void foo<T>::bar()':
test.cpp:7: error: expected `;' before "i"

Разве это не должно работать?

g ++ версия 3.4.3 на RHEL.

Ответы [ 3 ]

7 голосов
/ 11 июля 2009

Вы можете, но вы должны сказать ему, что iterator есть тип (он не знает, потому что в общем случае он может зависеть от T - так как vector является типом шаблона и может В теории есть специализации для некоторых T, где iterator - это функция или что-то еще). Таким образом, вы должны использовать typename, чтобы указать, что это всегда тип:

typename std::vector<T>::iterator i = x.begin();
1 голос
/ 11 июля 2009

Это должно сделать:

template<class T> class foo {

    void bar() {
        std::vector<T> x;
        typename std::vector<T>::iterator i = x.begin();

    }
};

Я процитирую руководство по компилятору IBM C ++:

Ключевое слово typename (только C ++). ключевое слово typename, если у вас есть квалифицированное имя, которое относится к типу и зависит от параметра шаблона. Используйте только ключевое слово typename в Шаблонные объявления и определения. Следующий пример иллюстрирует использование ключевого слова typename:

template<class T> class A
{
  T::x(y);
  typedef char C;
  A::C d;
}

Утверждение T :: x (y) неоднозначно. Это может быть вызовом функции x () с нелокальный аргумент у, или это может быть объявление переменной y с типом T :: x. C ++ будет интерпретировать это оператор как вызов функции. С целью для компилятора, чтобы интерпретировать это заявление в качестве декларации, вы бы добавьте ключевое слово typename к начало этого. Утверждение A :: C d; плохо сформирован. Класс А также относится до A и, таким образом, зависит от шаблона параметр. Вы должны добавить ключевое слово имя в начале этого Объявление:

имя типа A :: C d; Вы также можете использовать ключевое слово typename вместо класс ключевого слова в параметре шаблона декларации.

0 голосов
/ 11 июля 2009

В случае, если неясно, что другие подразумевают под компилятором, не зная, что это тип: в тот момент, когда компилятор анализирует шаблон foo, он не знает, что вы не сделаете позже:

namespace std {
    template<>
    class vector<int> {
        int iterator(void);
    };
}

А затем создать экземпляр foo<int>. Тогда vector<T>::iterator будет функцией, а не типом, и соответствующая строка в foo не сможет проанализировать. Чтобы работать без посторонней помощи, компиляторам пришлось бы задерживать синтаксический анализ foo до его создания, и они нашли правильный класс, чтобы определить, является ли 'iterator' выражением типа или выражением значения. Я подозреваю, что это может привести к циклическим зависимостям, но, безусловно, будет особенно трудно реализовать. Таким образом, стандарт говорит, что выражение в шаблоне, которое зависит от параметра, считается не типом, если не указано иное. Есть два (я думаю) способа объявить его типом, который (1) использует его как базовый класс и (2) квалифицирует его как имя типа.

ОК, так что в этом примере вам фактически не разрешено специализировать std :: vector. И в действительности вектор имеет больше параметров шаблона, чем тот, который я использовал. Так что в вашем примере компилятор может теоретически предполагать больше, чем делает. Но в стандарте не предусмотрено, чтобы язык полагался на знание того, какие шаблоны находятся в пространстве имен std, поскольку (1) предполагается, что реализации могут реализовывать пространство имен std в обычных заголовках, которые компилятор обрабатывает так же, как и любые другие заголовки и (2) C ++ должен быть спроектирован как язык + библиотеки, а не как «язык со специальным синтаксисом для библиотек». Фактически, (1) и (2) являются одним и тем же требованием.

...