首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >具有指定模板参数的C++11 make_pair无法编译

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

Stack Overflow用户
提问于 2012-03-10 06:41:36
回答 1查看 27.3K关注 0票数 85

我只是在玩启用了-std=c++11的g++ 4.7 (后来的快照之一)。我试图编译一些现有的代码库,但有一个案例失败了,这让我有点困惑。

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

代码如下:

代码语言:javascript
复制
#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)),但我不明白为什么在这种情况下它会失败。

确切的错误是:

代码语言:javascript
复制
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<class _T1, class _T2> constexpr std::pair<typename std::__decay_and_strip<_T1>::__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<char>}’) to type ‘std::basic_string<char>&&’

同样,这里的问题只是“发生了什么?”我知道我可以通过删除模板规范来解决这个问题,但我只想知道在幕后到底出了什么问题。

  • g++ 4.4编译此代码时没有problems.
  • Removing -std=c++11也编译代码时没有问题。
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-03-10 07:14:24

这不是std::make_pair的用法;您不应该显式地指定模板参数。

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

代码语言:javascript
复制
template <typename T, typename U>
[return type] make_pair(T&& argT, U&& argU);

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

代码语言:javascript
复制
[return type] make_pair(std::string&& argT, int&& argU);

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

那么,当您不显式指定模板参数列表中的TU是什么时,它为什么会起作用呢?简而言之,右值引用参数在模板中是特殊的。部分由于名为reference collapsing的语言特性,类型为A&&的右值引用参数(其中A是模板类型参数)可以绑定到任何类型的A

无论A是左值、右值、常量限定、易失性限定还是非限定,A&&都可以绑定到该对象(同样,当且仅当A本身是模板参数时)。

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

代码语言:javascript
复制
make_pair(s, 7)

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

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

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

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

如果模板参数可以从函数参数中推导出来,就让它被推导出来吧。除非万不得已,否则不要显式地提供参数。

让编译器来做这些繁重的工作,99.9%的时间都是你想要的。当它不是你想要的时候,你通常会得到一个很容易识别和修复的编译错误。

票数 138
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9641960

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档