Tuesday, March 30, 2010

Fail to overload

I had quirk with a failing overload resolution recently.

Probably you use this code all the time:

  vector<string> args;
// ..fill args...
process( args.begin(), args.end() );

while process is a vsersatille thing that you defined yourself in the STL way:
  template<typename> void process(const IT begin, const IT end);

Ok, so far so good, this will work. But notice what happens if you grab yourself the begin beforehand, because you need it:
  vector<string>::const_iterator it = args.begin();
it++; // skip first
process( it, args.end() );

Now, you'll get an error! No matching function found!

This is because in this case args.end() will return a "iterator" to you (not a "const_iterator") -- because it can. And you defined "it" to be a "const_iterator" -- so two different types. This will not match the process signature. Fail!
The solution is to use instead
  vector<string>::iterator it = args.begin();

or just "args.begin()+1" directly as the argument.

Pity, we learned to prefer using const if we can, ot here const_iterator, and because the compiler thinks it is smart, it fails.

But wait! Luckily this can be solved much better, still! But only with C++0x (or should I say C++11?). The Key "perfect forwarding" of arguments. If I understand this blog correclty this could also apply here. An appropriate foward could solve this, right?