C++0x中std::make_tuple存在问题

5
尝试使用Visual Studio 10编译以下程序,我得到了很多编译错误:
#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;
}

错误 1 错误 C2664: 'std::basic_string<_Elem, _Traits, _Ax>::basic_string(const std::basic_string<_Elem, _Traits, _Ax> &)':无法将参数 1 从 'const key_t' 转换为 'const std::basic_string<_Elem, _Traits, _Ax> &'。发生在此行:

这个错误发生在使用元组(tuple)时,因为参数类型不匹配。需要将参数转换为正确的类型。

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

奇怪的事情是,至少从我的角度来看,如果我更改这些行:
auto k = std::make_tuple("one", "two");
the_map[k] = "the value";

为了

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

程序已经编译通过。所以我的问题当然是为什么?我猜测这与make_tuple和移动语义有关,但我不明白具体是什么。

2个回答

5
显然,错误实际上来自于这一行:the_map[k] = "the value"; 当您在map上使用[]操作符时,库会尝试创建一个std::pair<Key,Value>对象。在您的情况下,它变成了std::pair<std::tuple<std::string,std::string>,std::string>
但是,如果您使用中间变量k,则调用的std::pair构造函数如下(从标准库复制粘贴):
_Pair_base(const _Ty1x& _Val1, _Ty2x&& _Val2)
        : first(_Val1), second(_STD move(_Val2))
        {   // construct from specified values
        }

这个构造函数试图复制你的key_t。不幸的是,MSVC++的tuple实现目前存在缺陷,拷贝无法通过编译(详情请见:C++0x:是否允许使用元组的元组?)。

我可以做更多的诊断,因为这个实现不仅有缺陷,而且非常复杂。

Boost的tuples应该可以工作,但没有一个<运算符,所以你不能使用它们。

目前“最好”的解决方案是写 the_map.insert(std::make_pair(k, "the value"));


谢谢 - 它可以工作了,我的原始代码在你的修复下看起来还不错。 - baardk
请注意,您也可以编写 the_map[std::move(k)] = "the value",但这会“销毁”您的 k 变量(如果您不知道我所说的“销毁”是什么意思,请查看一些关于移动语义的文章)。 - Tomaka17
好的。我已经在某些微软连接网站上发布了这个问题,这样他们就可以检查是否存在Bug或其他问题了。 - baardk

2
这似乎是VS10中的一个bug,出于某种原因它试图将键类型转换为值类型。
这个简化版本也失败了。
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;

产生以下结果:

错误 C2440:'initializing':无法将'const std::tr1::tuple<_Arg0,_Arg1>'转换为'int'


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接