views:

88

answers:

2

I'm trying to write a function to print a representation of common STL containers (vector, list, etc..). I gave the function a template parameter T which, for example, might represent vector. I'm having problems getting an iterator of type 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

I tried 'typename T::iterator' as the compiler suggested, but only got a more cryptic error.

Edit: Thanks for the help guys! Here's a working version for anyone who wants to use this function:

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";
}
+6  A: 

You need typename to tell the compiler that ::iterator is supposed to be a type. The compiler doesn't know that it's a type because it doesn't know what T is until you instantiate the template. It could also refer to some static data member, for example. That's your first error.

Your second error is that v is a reference-to-const. So, instead of ::iterator you have to use ::const_iterator. You can't ask a constant container for a non-const iterator.

sellibitze
Who downvoted this answer? The answer is correct.
Prasoon Saurav
Not so much that the compiler doesn't know what `::iterator` is, but the standard requires it to interpret it as a non-type, as it is nicely put in the error message: "dependent-name ‘`T::iterator`’ is parsed as a non-type, but instantiation yields a type"
visitor
I see. So, this hair splitting justifies a downvote.
sellibitze
@visitor: With a correct two-phase implementation (read "not MSVC") the compiler can't know what `iterator` is in the first pass because the template parameters are not set yet. See e.g. item 6 and 7 [here](http://womble.decadent.org.uk/c++/template-faq.html#disambiguation).
Georg Fritzsche
+4  A: 

Change T::iterator i; to typename T::const_iterator i; because ::iterator is of type T and v is a const &.

Before a qualified dependent type, you need typename. Without typename, there is a C++ parsing rule that says that qualified dependent names should be parsed as non-types even if it leads to a syntax error.

typename states that the name that follows should be treated as a type. Otherwise, names are interpreted to refer to non-types.

Prasoon Saurav