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

C++11 make_pair with specified template parameters doesn't compile

我只是玩G+ + 4.7(稍后的快照之一),启用了STD=C++ 11。我试图编译一些现有的代码库,有一个失败的案例让我有些困惑。

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

下面是代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#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: In function ‘int main()’:
test.cpp:11:83: error: no matching function for call to ‘make_pair(std::string&, int)’
test.cpp:11:83: note: candidate is:
In file included from /gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/utility:72:0,
from 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: cannot 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 EDOCX1×0的两个参数是EDCOX1,2,EDCX1,3,EDCX1,4,EDCX1,5是模板类型参数。实际上,它看起来像这样(忽略返回类型):

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

当调用std::make_pair并显式指定模板类型参数时,不会进行参数推导。相反,类型参数直接替换到模板声明中,从而产生:

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

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

那么,当您没有明确指定模板参数列表中的TU时,为什么它会起作用?简言之,右值引用参数在模板中是特殊的。由于一种称为引用折叠的语言特性,类型A&&的右值引用参数(其中A是模板类型参数)可以绑定到任何类型的A上。

不管A是左值、右值、const-qualified、volatile-qualified还是unqualified,A&&都可以绑定到该对象(同样,如果并且仅当A本身是模板参数时)。

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

1
make_pair(s, 7)

这里,sstd::string型的左值,7int型的右值。由于没有为函数模板指定模板参数,因此将执行模板参数推断以确定参数是什么。

为了将左值s绑定到T&&,编译器将T推断为std::string&,生成std::string& &&类型的参数。但是没有引用,所以这个"双引用"折叠成了std::string&s是一个匹配项。

7绑定到U&&很简单:编译器可以将U推断为int,生成int&&类型的参数,因为它是一个右值,所以成功绑定到7上。

这些新的语言特性有很多微妙之处,但是如果您遵循一个简单的规则,这很容易:

If a template argument can be deduced from the function arguments, let it be deduced. Don't explicitly provide the argument unless you absolutely must.

Let the compiler do the hard work, and 99.9% of the time it'll be exactly what you wanted anyway. When it isn't what you wanted, you'll usually get a compilation error which is easy to identify and fix.