具有指定模板参数的C ++ 11 make_pair不能编译

我正在玩g ++ 4.7(以后的快照之一),启用了-std = c ++ 11。 我试图编译一些我现有的代码库和一个失败的混淆我的案例。

如果有人能解释发生了什么,我将不胜感激。

这是代码

#include <utility> #include <iostream> #include <vector> #include <string> int main ( ) { std::string s = "abc"; // 1 ok std::pair < std::string, int > a = std::make_pair ( s, 7 ); // 2 error on the next line std::pair < std::string, int > b = std::make_pair < std::string, int > ( s, 7 ); // 3 ok std::pair < std::string, int > d = std::pair < std::string, int > ( s, 7 ); return 0; } 

我明白,make_pair是用来作为(1)的情况下(如果我指定的types,那么我也可以使用(3)),但我不明白为什么它在这种情况下失败。

确切的错误是:

test.cpp:在函数'int main()'中:test.cpp:11:83:error:没有匹配函数调用'make_pair(std :: string&,int)'test.cpp:11:83:候选人是:从/gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7包含的文件。 0 / utility:72:0,从test.cpp:1:/gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../。 ./include/c++/4.7.0/bits/stl_pair.h:274:5:note:template constexpr std :: pair :: __ type,typename std :: __ decay_and_strip <_T2> :: __ type> std :: make_pair(_T1 && ,_T2 &&)/gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/ stl_pair.h:274:5:note:template argument deduction / substitution failed:test.cpp:11:83:note:can not convert's'(type'std :: string {aka std :: basic_string}')to type '的std :: basic_string的&&'

再次,这里的问题只是“发生了什么事?” 我知道我可以通过删除模板规范来解决这个问题,但是我只想知道封面下面的失败。 提前致谢。

编辑:

  • g ++ 4.4编译这个代码没有问题。
  • 删除-std = c ++ 11也可以用没有问题的代码编译。

这不是如何使用std::make_pair ; 你不应该明确指定模板参数。

C ++ 11 std::make_pair接受两个types为T&&U&& ,其中TU是模板types参数。 实际上,它看起来像这样(忽略返回types):

 template <typename T, typename U> [return type] make_pair(T&& argT, U&& argU); 

当你调用std::make_pair并显式指定模板types参数时,不会发生任何参数推导。 而是将types参数直接replace为模板声明,得到:

 [return type] make_pair(std::string&& argT, int&& argU); 

请注意,这两个参数types都是右值引用。 因此,他们只能绑定到右值。 这对于你传递的第二个参数7来说不是问题,因为这是一个右值expression式。 然而,这是一个左值expression式(它不是一个临时的,也没有被移动)。 这意味着函数模板与您的参数不匹配,这就是您得到错误的原因。

那么,为什么当你没有明确指定模板参数列表中的TU时,它会起作用? 简而言之,右值引用参数在模板中是特殊的。 部分由于引用了参考折叠的语言特性,typesA&&的右值引用参数(其中A是模板types参数)可以绑定到任何types的A

无论A是左值还是右值,const限定,volatile限定或不合格, A&&都可以绑定到该对象(当且仅当A本身是模板参数时)。

在你的例子中,我们打电话:

 make_pair(s, 7) 

这里sstd::stringtypes的左值, 7inttypes的右值。 由于您没有为函数模板指定模板参数,因此执行模板参数推导来确定参数是什么。

为了将s ,一个左值绑定到T&& ,编译器将T&&推导为std::string& ,产生一个types为std::string& && 。 虽然没有引用的引用,所以这个“双引用”崩溃成为std::string&s是一场比赛。

绑定7U&&很简单:编译器可以推导出Uint ,产生一个int&&types的参数,它成功绑定到7因为它是一个右值。

这些新的语言function有很多细微之处,但是如果遵循一个简单的规则,这很简单:

如果可以从函数参数中推导出一个模板参数,那就推导出来。 除非你绝对必须,否则不要明确提供论据。

让编译器努力工作,99.9%的时间完全是你想要的。 当它不是你想要的,你通常会得到一个易于识别和修复的编译错误。