【问题标题】:Breaking change in C++11 with make_pair(_Ty1&& _Val1, const _Ty2& _Val2)使用 make_pair(_Ty1&& _Val1, const _Ty2& _Val2) 在 C++11 中进行重大更改
【发布时间】:2013-01-15 10:43:14
【问题描述】:

考虑以下 C++ 程序

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

使用 VC11 以及在 gcc-4.7.2 fails 中出现不同的错误,虽然它似乎是相关的并且 VC11 错误消息更有意义

You cannot bind an lvalue to an rvalue   

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

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

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

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

【问题讨论】:

  • 好吧,这不是一个重大变化,因为到底谁使用std::make_pair 和显式模板实例化?它明确设计以从自动类型推断中获利。因此,由于很少有人会写std::make_pair&lt;int,int&gt; 来支持std::make_pair,因此没有多少代码需要破解。不过,不错的发现。
  • 不幸的是,我遇到了指定显式类型的代码。
  • 我相信这与http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43785讨论的问题相同

标签: c++ visual-c++ stl c++11 g++


【解决方案1】:

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

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

如果你想显式地输入类型,你可以使用 pair 构造函数。它甚至更短......

auto pair = std::pair<int, int>(a,b);

【讨论】:

  • 感谢您的回答。我虽然很难理解上述事实。顺便说一句,你能解释一下universal reference 是什么意思吗?这个词对我来说是新的。您还知道其他类似更改的库函数吗?
  • @Abhijit 我添加了一个指向 Scott Meyer 解释的链接(他想出了这个词)。如果您不使用类型推导,则任何其他用于相同目的(利用类型推导)的库函数都可能不起作用。它们通常采用make_something 的形式,例如make_tuple。关键是它们不适用于显式类型,因为它们不适用于显式类型。
  • @Abhijit 明确地说,“通用参考”只是一个口语术语。它们实际上只是右值引用,但由于模板类型推导和引用折叠规则,它们有一个有趣的属性——它们有时表现得像左值引用,有时表现得像右值引用。想想看,我们应该称之为lvalue-rvalue duality
  • 感谢您和@sftrabbit 花时间回答我的疑问。
【解决方案2】:

当您执行std::make_pair&lt;int, int&gt; 时,您将强制将模板参数T1T2 都推导出为int。这为您提供了std::pair&lt;int,int&gt; make_pair(int&amp;&amp;, int&amp;&amp;) 的功能。现在这些参数只能采用右值,因为它们是右值引用。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-03
    • 1970-01-01
    • 2014-02-26
    • 2016-01-08
    • 1970-01-01
    • 2020-10-02
    • 1970-01-01
    • 2019-11-08
    相关资源
    最近更新 更多