The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

Can't iterate list<T> in C++ template function.

I've got a template function that accepts a list of T and tries to iterate through it, but the compiler is giving me errors I can't figure out:

template <class T>
object_out_streamer& object_out_streamer::operator<<(std::list<T> &objects)
{
    bool first = true;
    for(std::list<T>::iterator i = objects.begin(); i != objects.end(); i++)
    {
        // do stuff
    }
}

The line with the for(;;) is getting these errors:
Severity and Description    Path    Resource    Location    Creation Time    Id
error: `i' undeclared (first use this function)    DciApi    object_out_streamer.hpp    line 51    1178516562698    6583
error: dependent-name ` std::list<T,std::allocator<_CharT> >::iterator' is parsed as a non-type, but instantiation yields a type    DciApi    object_out_streamer.hpp    line 51    1178516562698    6586
error: expected `;' before "i"    DciApi    object_out_streamer.hpp    line 51    1178516562698    6582

Any help is greatly appreciated!
Ugnonimous
Monday, May 07, 2007
 
 
What is your operator<< - a member template? Please provide the declaration for object_out_streamer.
Micha Send private email
Monday, May 07, 2007
 
 
Because list<T> is a template, the compiler can't figure out what kind of thing list<T>::iterator is. You need to add the typename keyword to help the compiler:

for (typename std::list<T>::iterator i = objects.begin(); i != objects.end(); i++)
Frederik Slijkerman
Monday, May 07, 2007
 
 
A good trick with templated types is to always typedef them. That generally makes catching misformed types simpler.

typedef std::list<T>::iterator ListIterator;

This should catch the problem earlier where it's easier to separate from the other code.
Coopsnakes Send private email
Monday, May 07, 2007
 
 
May I add some points about the correctness of this code ?

You should be using a const std::list<T> as argument and a std::list<T>::const_iterator to iterate. If your operator just print (which it seems to do) then you can work with const Ts. Using const for iterations is usually a good idea because it helps prevent mistakes.

Instead of using a loop, you should be using an algorithm, std::for_each in this case. Algorithms are faster, safer and designed exactly for that purpose. I will personnaly add that I find them more readable.

Const-correctness
http://www.gotw.ca/gotw/006.htm


STL Algorithms vs. Hand-Written Loops
http://www.ddj.com/dept/cpp/184401446
Vincent Robert Send private email
Monday, May 07, 2007
 
 
Frederik - That fixed the problem, thanks!

Vincent - I've taken your advice on the const and it cleared up another compiler error, but I'm not sure why. (I haven't gotten to algorithms yet).

In my class header I've got these declarations:

object_out_streamer &operator<<(const std::list<std::string> &values);
template <class T>
object_out_streamer &operator<<(std::list<T> &objects);

The second you'll recognize is the declaration of the function template that started this thread. 

The template function now looks like this:
template <class T>  // T must implement streamable
object_out_streamer& object_out_streamer::operator<<(std::list<T> &objects)
{
    bool first = true;
    for(typename std::list<T>::iterator i = objects.begin(); i != objects.end(); i++)
    {
        if(!first)
        {
            *_out << LIST_SEPARATOR;
        }
        first = false;
        i->write_components(*this);  <--error here
    }
            
    return *this;
}

And the error message is:
Severity and Description    Path    Resource    Location    Creation Time    Id
error: 'struct std::basic_string<char, std::char_traits<char>, std::allocator<char> >' has no member named 'write_components'    DciApi    object_out_streamer.hpp    line 59    1178549172582    6701

Which I think means that somewhere else in my code I've code a list<string> that I'm trying to call << on, but the compiler is instead sending it into the list<T> version of the << operator.

Now here's the part I don't get.  Following Vincent's advice I changed the template function to take const list<T>:

    template <class T>
    object_out_streamer &operator<<(const std::list<T> &objects);

And that clears up the problem.  Now it compiles fine.  Why?

Thanks again, you guys are great!
Ugnonimous
Monday, May 07, 2007
 
 
@Ugnonimous,

An issue with your questions is the sometimes missing context. What are the circumstances of calling op<<? It _seems_ you'll call them with a non-constant string, so the compiler chooses not the string variant, but a specialization of the template op<< (specialized to 'string'). After changing the signature, all goes well and he picks up the explicitely declared const_string op<<
But no-one knows for sure. I have to admit, at times the rules for overloading / specialization / instantiation of C++ templates are hard to grasp. Something I can recommend here is:

http://tinyurl.com/24d6kf

After reading it, you should be quite comfortable with these topics.
Micha Send private email
Monday, May 07, 2007
 
 
I find with Visual Studio, the errors I get in the 'output' window are in the order encountered, and in the 'task' window, another order. Fixing the first actual error often causes others to dissapear. So make sure you're fixing actual errors, and not the result of a compiler confused by previous errors.

Tuesday, May 08, 2007
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz