20

考虑以下 C++ 程序

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

在gcc-4.7.2中使用 VC11失败并出现不同的错误,尽管它似乎是相关的并且 VC11 错误消息更有意义

You cannot bind an lvalue to an rvalue   

我从这次失败中了解到的是

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

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

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

2 回答 2

22

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

template <class T1, class T2>
constexpr pair<V1, V2> make_pair(T1&& x, T2&& y);

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

auto pair = std::pair<int, int>(a,b);
于 2013-01-31T10:58:16.813 回答
18

当你这样做时std::make_pair<int, int>,你将强制模板参数T1T2都被推导出为int. 这为您提供了std::pair<int,int> make_pair(int&&, int&&). 现在这些参数只能采用右值,因为它们是右值引用。

但是,当 和 的类型T1T2模板类型推导推导时,它们充当“通用引用”。也就是说,如果他们收到一个左值参数,他们将是左值引用,如果他们收到一个右值参数,他们将是右值引用。这提供make_pair了进行完美转发的能力。

所以重点是,不要显式地给出模板类型参数。的全部意义make_pair在于它推断出类型本身。如果您命名类型,它就不能再进行完美转发,并且对于左值参数将失败。

于 2013-01-31T11:01:46.777 回答