views:

174

answers:

2

Tying to compile the following program with Visual Studio 10, I get lot of compile errors:

#include "stdafx.h"

#include <tuple>
#include <string>
#include <map>
#include <iostream>

int _tmain(int argc, _TCHAR* argv[])
{
    typedef std::tuple<std::string, std::string> key_t;
    typedef std::map<key_t, std::string> map_t;

    map_t the_map;

    auto k = std::make_tuple("one", "two");
    the_map[k] = "the value";

    auto  q = std::make_tuple("one", "two");

    auto  i = the_map.find(q);
    std::cout << i->second << std::endl;

    return 0;
}

Error 1 error C2664: 'std::basic_string<_Elem,_Traits,_Ax>::basic_string(const std::basic_string<_Elem,_Traits,_Ax> &)' : cannot convert parameter 1 from 'const key_t' to 'const std::basic_string<_Elem,_Traits,_Ax> &' c:\program files (x86)\microsoft visual studio 10.0\vc\include\tuple 127 1 tuple

Coming from the line:

std::cout << i->second << std::endl;

Strange thing is, as least from my point of view, if I change these lines:

auto k = std::make_tuple("one", "two");
the_map[k] = "the value";

to

the_map[std::make_tuple("one", "two")] = "p";

the program compiles. So my question is of course why? I guess it has something to do with make_tuple and move semantics - but I do not understand what..

+2  A: 

Apparently the error comes in fact from the line the_map[k] = "the value";

When you use the [] operator on a map, the library tries to create a std::pair<Key,Value> object. In your case, this becomes std::pair<std::tuple<std::string,std::string>,std::string>.

However if you use an intermediate variable k, the constructor of std::pair which is called is: (copy-pasted from the standard lib)

_Pair_base(const _Ty1x& _Val1, _Ty2x&& _Val2)
        : first(_Val1), second(_STD move(_Val2))
        {   // construct from specified values
        }

This constructor is trying to make a copy of your key_t. Unfortunatly, the tuple implementation of MSVC++ is bugged at the moment and the copy fails to compile (see also this: http://stackoverflow.com/questions/3254427/c0x-are-tuples-of-tuples-allowed)

I can diagnosize more, because this implementation is not only bugged but also very complicated.

Boost's tuples should work but don't have an < operator, so you can't use them.

The "best" solution for the moment is to write the_map.insert(std::make_pair(k, "the value"));

Tomaka17
Thanks - it works and my original code will look okay with your fix.
baardk
Note that you can also write `the_map[std::move(k)] = "the value"` but this will "destroy" your `k` variable (look at some articles about move semantics if you don't see what I mean by destroy).
Tomaka17
Nice. I posted the problem on some MS connect site, so they can check if it is a bug or what.
baardk
+1  A: 

This looks like a bug in VS10, for some reason it's trying to cast the key type to the value type.

This simplified version also fails.

typedef std::map<std::tuple<int, int>, int> map_t;

map_t the_map;

map_t::key_type k = std::make_tuple(1,2);
the_map[k] = 3;

Produces the following:

error C2440: 'initializing' : cannot convert from 'const std::tr1::tuple<_Arg0,_Arg1>' to 'int'

Motti
Ah, nice simplification.
baardk