带有指定模板参数的C ++ 11 make_pair无法编译

时间:2012-03-09 22:41:36

标签: c++ templates g++ c++11 rvalue-reference

我正在使用启用了-std = c ++ 11的g ++ 4.7(后一个快照之一)。我试图编译一些现有的代码库,一个失败的案例让我感到困惑。

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

这是代码

#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)情况(如果我指定类型,那么我不妨使用(3)),但我不明白为什么在这种情况下失败了。

确切的错误是:

  

test.cpp:在函数'int main()'中:       test.cpp:11:83:错误:没有匹配函数来调用'make_pair(std :: string&amp;,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:   注意:模板constexpr std :: pair :: __ type,typename   的std :: __ decay_and_strip&LT; _T2&GT; :: __类型&GT; std :: make_pair(_T1&amp;&amp;,_T2&amp;&amp;)       /gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/stl_pair.h :274:5:   注意:模板参数扣除/替换失败:       test.cpp:11:83:注意:不能将's'(类型'std :: string {aka std :: basic_string}')转换为'std :: basic_string&amp;&amp;'

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

编辑:

  • g ++ 4.4编译此代码没有任何问题。
  • 删除-std = c ++ 11也可以编译代码而没有任何问题。

1 个答案:

答案 0 :(得分:117)

这不是std::make_pair的意图;你不应该明确指定模板参数。

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

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

当您调用std::make_pair并显式指定模板类型参数时,不会发生参数推断。相反,类型参数直接替换为模板声明,产生:

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

请注意,这两个参数类型都是右值引用。因此,它们只能绑定到右值。对于传递的第二个参数7,这不是问题,因为这是一个右值表达式。但是,s是一个左值表达式(它不是临时的,它不会被移动)。这意味着函数模板与您的参数不匹配,这就是您收到错误的原因。

那么,为什么当你没有明确指定模板参数列表中的TU时,它是否有效?简而言之,右值参考参数在模板中是特殊的。部分由于名为引用折叠的语言功能,类型为A&&的右值引用参数(其中A是模板类型参数)可以绑定到任何类型的{{} 1}}。

A是左值,右值,const限定,volatile限定还是不合格无关紧要,A可以绑定到该对象(同样,只有...如果A&&本身就是模板参数。)

在您的示例中,我们进行了调用:

A

此处,make_pair(s, 7) s类型的左值,std::string是类型7的左值。由于您没有为函数模板指定模板参数,因此执行模板参数推导以确定参数是什么。

要将int(左值)绑定到s,编译器会将T&&推导为T,从而产生类型为std::string&的参数。但是,没有对引用的引用,因此这个“双引用”会折叠成std::string& &&std::string&是匹配。

s绑定到7很简单:编译器可以将U&&推导为U,从而产生类型int的参数,该参数成功绑定至int&&,因为它是一个右值。

这些新的语言功能有很多微妙之处,但是如果你遵循一个简单的规则,那就很容易了:

  

如果可以从函数参数中推导出模板参数,那么可以推导出它。除非绝对必须,否则不要明确提供参数。

     

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