用make_pair打破C++ 11的变化(_Ty1 && _Val1,const _Ty2&_Val2)

Abh*_*jit 19 c++ stl g++ visual-c++ c++11

请考虑以下C++程序

#include<map>
#include<iostream>
int main() {
    int a = 5, b = 7;
    auto pair = std::make_pair<int, int>(a,b);
    return 0;
    }
Run Code Online (Sandbox Code Playgroud)

使用VC11和gcc-4.7.2也会出现不同的错误,虽然它似乎是相关的,VC11错误信息更有意义

You cannot bind an lvalue to an rvalue   
Run Code Online (Sandbox Code Playgroud)

我从这次失败中理解的是

  1. VC11和我认为gcc-4.7.2只有一个std :: make_pair实现,make_pair(_Ty1&& _Val1, const _Ty2& _Val2)它只能接受一个右值引用.以前的VC++版本示例VC10有两个版本,一个是接受左值,另一个是右值引用
  2. Rvalue引用不能用于初始化非const引用,即int & a = b * 5无效.
  3. 我本可以用来std::move转换lvaluervalue引用,并且调用将成功.
  4. 由于std::make_pair每个参数都接受两种不同的类型,因此在所有可能的情况下,模板参数解析可以解析参数的类型,并且不需要显式指定类型.

这种情况似乎微不足道,通过删除显式类型规范并将定义定义为,可以轻松解决不兼容问题

auto pair = std::make_pair(a,b);
Run Code Online (Sandbox Code Playgroud)
  • 现在,我的问题是,从库中删除左值实现的驱动因素是什么?
  • 是否有可能知道以类似方式更改的任何其他库函数?
  • 当我需要针对多个编译器(如g ++,CC,aCC,XL C++,其中编译器尚未升级或编译器不支持rvalue引用和/或移动语义)时,如何处理这些情况.

R. *_*des 20

std::make_pair 存在的唯一目的是利用类型推导来避免键入类型的名称.这就是为什么只有一个重载(它应该采用两个通用引用,而不是一个通用引用和一个对VC的左值引用,因为VC似乎认为).

template <class T1, class T2>
constexpr pair<V1, V2> make_pair(T1&& x, T2&& y);
Run Code Online (Sandbox Code Playgroud)

如果要显式键入类型,可以使用对构造函数.它甚至更短......

auto pair = std::pair<int, int>(a,b);
Run Code Online (Sandbox Code Playgroud)

  • @Abhijit需要明确的是,“通用参考”只是一个口语术语。它们实际上只是右值引用,但由于模板类型推导和引用折叠规则,它们有一个有趣的属性 - 它们有时表现得像左值引用,有时又像右值引用。想想看,我们应该称之为“左值-右值二元性”。 (2认同)

Jos*_*eld 18

当你这样做时std::make_pair<int, int>,你正在强制模板参数,T1T2推断为int.这给你的功能std::pair<int,int> make_pair(int&&, int&&).现在这些参数只能采用rvalues,因为它们是rvalue引用.

但是,当模板类型推导的类型T1T2推导时,它们充当"通用引用".也就是说,如果它们接收到左值参数,它们将是左值引用,如果它们接收到右值参数,它们将是右值引用.这使得make_pair能够进行完美的转发.

所以重点是,不要显式给出模板类型参数.重点make_pair在于它推断了类型本身.如果您为类型命名,则它不能再完美转发,并且对于左值参数将失败.