Ошибка с T::iterator, где параметр шаблона T может быть vector‹int› или list‹int›

Я пытаюсь написать функцию для печати представления общих контейнеров STL (вектор, список и т.д.). Я дал функции шаблонный параметр T, который, например, может представлять собой вектор. У меня проблемы с получением итератора типа T.

vector<int> v(10, 0);
repr< vector<int> >(v);

...

template <typename T>
void repr(const T & v)
{
    cout << "[";
    if (!v.empty())
    {
        cout << ' ';
        T::iterator i;
        for (i = v.begin(); 
             i != v.end()-1;
             ++i)
        {
            cout << *i << ", ";
        }
        cout << *(++i) << ' ';
    }
    cout << "]\n";
}

...

brett@brett-laptop:~/Desktop/stl$ g++ -Wall main.cpp
main.cpp: In function ‘void repr(const T&)’:
main.cpp:13: error: expected ‘;’ before ‘i’
main.cpp:14: error: ‘i’ was not declared in this scope
main.cpp: In function ‘void repr(const T&) [with T = std::vector<int, std::allocator<int> >]’:
main.cpp:33:   instantiated from here
main.cpp:13: error: dependent-name ‘T::iterator’ is parsed as a non-type, but instantiation yields a type
main.cpp:13: note: say ‘typename T::iterator’ if a type is meant

Я попробовал «typename T::iterator», как предложил компилятор, но получил только более загадочную ошибку.

Редактировать: Спасибо за помощь, ребята! Вот рабочая версия для тех, кто хочет использовать эту функцию:

template <typename T>
void repr(const T & v)
{
    cout << "[";
    if (!v.empty())
    {
        cout << ' ';
        typename T::const_iterator i;
        for (i = v.begin(); 
             i != v.end();
             ++i)
        {
            if (i != v.begin())
            {
                cout << ", ";
            }
            cout << *i;
        }
        cout << ' ';
    }
    cout << "]\n";
}

person bretttolbert    schedule 17.09.2010    source источник
comment
Как насчет публикации более загадочного сообщения об ошибке?   -  person CB Bailey    schedule 17.09.2010
comment
Кстати, вы можете заменить v.end()-1 чем-то другим, что также поддерживают не RandomAccess-итераторы.   -  person sellibitze    schedule 17.09.2010


Ответы (2)


Вам нужно typename, чтобы сообщить компилятору, что ::iterator должен быть типом. Компилятор не знает, что это тип, потому что он не знает, что такое T, пока вы не создадите экземпляр шаблона. Например, это может также относиться к некоторому статическому члену данных. Это твоя первая ошибка.

Ваша вторая ошибка заключается в том, что v является ссылкой на const. Итак, вместо ::iterator вы должны использовать ::const_iterator. Вы не можете запрашивать у константного контейнера неконстантный итератор.

person sellibitze    schedule 17.09.2010
comment
Не то чтобы компилятор не знал, что такое ::iterator, но стандарт требует, чтобы он интерпретировал его как не-тип, как это прекрасно указано в сообщении об ошибке: зависимое-имя 'T::iterator' анализируется как не-тип. тип, но создание экземпляра дает тип - person visitor; 17.09.2010
comment
@visitor: при правильной двухфазной реализации (читай, не MSVC) компилятор не может знать, что такое iterator в первом проходе, потому что параметры шаблона еще не установлены. См., например. пункты 6 и 7 здесь. - person Georg Fritzsche; 17.09.2010

Замените T::iterator i; на typename T::const_iterator i;, потому что ::iterator имеет тип T, а v — это const &.

Перед квалифицированным зависимым типом вам нужно typename. Без typename существует правило синтаксического анализа C++, согласно которому квалифицированные зависимые имена должны анализироваться как non-types, даже если это приводит к синтаксической ошибке.

typename указывает, что следующее за ним имя следует рассматривать как тип. В противном случае имена интерпретируются как ссылки на не-типы.

person Prasoon Saurav    schedule 17.09.2010