VC 2005 Express - Compiler error using STL

Started by
8 comments, last by virtuallyrandom 16 years, 9 months ago
Hey all, I can't believe that I can't figure this out, but... I need some help. :) I'm using VC++ 2005 Express (fairly new to it as well) and I'm trying to get some code to compile. It's giving me a Ton of errors and I don't understand why. I'm also fairly new to the STL (aka, haven't used it in 7+ years...) so combining the two is causing me some grief at the moment. :) Anyways, the code below is producing the error:
c:\directory\path\node.h(27) : error C2784: 'bool std::operator <(const std::_Tree<_Traits> &,const std::_Tree<_Traits> &)' : could not deduce template argument for 'const std::_Tree<_Traits> &' from 'std::_Tree<_Traits>::const_iterator'
        with
        [
            _Traits=std::_Tmap_traits<std::string,std::string,std::less<std::string>,std::allocator<std::pair<const std::string,std::string>>,true>
        ]
        c:\program files\microsoft visual studio 8\vc\include\xtree(1372) : see declaration of 'std::operator <'
#include <string>
#include <map>

class Node
{
    public:
        typedef std::multimap<std::string, std::string> nodemap;

        operator const char*(void) const { return name.c_str(); }

        std::string name;

        void logit(void) const
        {
            nodemap::const_iterator i;

            if (map.empty()) return;

            for (i = map.begin(); i < map.end(); i++) /* ERROR */
            {
            }
        }

    private:
        nodemap map;

    friend class NodeMap;
};
Commenting out the for loop kills the error, but here's something else that's got me stumped... Changing the code to this changes where the error is:
        void logit(void) const
        {
            nodemap::const_iterator i = map.begin(); /* works fine! */

            if (i == map.end()) return; /* works fine! */

            while (i < map.end()) /* ERROR */
            {
                i++;
            }
        }
Anybody have a clue as to what gives? Thanks! vr
Advertisement
You should always use the != operator to compare your iterator against end(), instead of operator<, the reason being that the relationship between successful iterators is not always the same as that for plain pointers (i.e. in an array or std::vector, successive elements always have a higher address in memory, so operator< works fine, but this is not always the case).

for (i = whatever.begin(); i != whatever.end(); ++it)    ...


EDIT: went and found a source to back me up. From Herb Sutter (http://www.gotw.ca/gotw/073.htm):

"13. Reuse Part 4, or Prefer comparing iterators using !=: When comparing iterators, always use != (which works for all kinds of iterators) instead of < (which works only for random-access iterators), unless of course you really need to use < and only intend to support random-access iterators. The original program uses < to compare the iterators it's given to work on, which is fine for random access iterators, which was the program's initial intent -- to create indexes into vectors and arrays, both of which support random-access iteration. But there's no reason we may not want to do exactly the same thing for other kinds of containers, like lists and sets, that don't support random-access iteration, and the only reason the original code won't work for such containers is that it uses < instead of != to compare iterators."
It seems that the operator < is not defined.
Anyway, with STL iterators, when looping over them, you should use !=, because in certain containers, memory is not always aligned, and subsequent comparisons may be greater than or less than the previous one.

Try something like
[SOURCE]for (std::multimap<std::string, std::string>::const_iterator i = map.begin(); i != map.end(); ++i){ //Loopy.}[/SOURCE]
[/source]

[size=1]Visit my website, rawrrawr.com

oh geez...

bobofjoe and strtok, thanks, that was exactly it. :)

I've got some other code to go fix now too, hehe.

Thanks!!

vr
While I can see the code [smile]

        operator const char*(void) const { return name.c_str(); }


This makes me very suspicious. Are you doing this for the sake of debugging (by printing out the tree)? The proper way to support that is to overload operator<< for the class. Also, in modern C++, prefer () prototypes instead of (void). It's simpler and more consistent ("(void)", interpreted by the same rules as every other prototype, makes it look like the function should take one argument of type 'void', which is clearly nonsense).
The code was there originally for debugging, I just haven't taken it out yet.

The library that I use for debugging is in C and accepts input as a variable argument list. Originally, I was casting the Node to char*, but later decided it would be easier and faster to just put in a "logit" function, hehe.

Do you have any more info on the () vs. (void) prototyping? I put in void out of habit because I like to be extremely explicit.

Thanks!

vr
Quote:Original post by virtuallyrandomDo you have any more info on the () vs. (void) prototyping? I put in void out of habit because I like to be extremely explicit.


In C++, a function declared with no parameters take no parameters -- that's explicit. In C, a function taking no parameters take zero or more parameters, so the ISO committee introduced using the void keyword in the function prototype to make it explicit that the function takes zero and only zero parameters.

So, in short, a C function prototype with a single unnamed void parameter is the equivalent of a C++ function declaration taking no parameters at all. C++ maintains support for the single unnamed parameter of type void for backwards compatibility with C code.

The only thing you're being explicit about when using the single unnamed parameter of type void in C++ is that you learned ISO C before learning C++ and you haven't yet learned a lot about C++.

Stephen M. Webb
Professional Free Software Developer

Excellent explanation, thanks Bregma :)

My job requires me to use strict C all the time, so sometimes it's hard to get out of the "strict C" habit and into the C++ habit... the result of coding that way for a while, I guess...

vr
Unfortunately Bregma is wrong. Stroustrup introduced void as a function signature into C++ first (way back when it was still called C with Classes). The ISO C committee introduced the form afterwards. It's not in there for compatibility; you should read D&E sometime. And for the record I use void to signify a no argument function. I think you'll have a hard time arguing that I "haven't yet learned a lot about C++".
Thanks SiCrane, I'll take a look as soon as I get the time (short deadline task at the moment... yet here I am, typing away... /shrug)

It's amazing how much one can learn about something they thought they already knew by asking a totally unrelated question. ;)

Thanks!

vr

This topic is closed to new replies.

Advertisement