【问题标题】:Inconsistent overload resolution with rvalue references与右值引用不一致的重载解决方案
【发布时间】:2014-07-31 14:35:44
【问题描述】:

我对重载解析的理解是,'T&&' 通常比 'const T&' 更匹配。但是,通过这个简单的示例,我发现编译器之间存在一些不一致的行为:

#include <iostream>

void Func(const double& a)
{
    (void)a;
    std::cout << "[lvalue]\n";
}

void Func(double&& a)
{
    (void)a;
    std::cout << "[rvalue]\n";
}

template <typename T>
void TFunc(T&& a)
{
    Func(a);
}

int main ()
{
    TFunc(5.5f);

    return 0;
}

Clang 3.2 将打印 [rvalue]。但是,VS2013 32 位/64 位编译器会打印 [lvalue]。如果我将 '5.5f' 更改为 '5.5',那么两个编译器都会打印 [lvalue].

我可以理解为什么 VS 编译器选择 'const double&' 版本,因为我没有 std::forward 调用来保留参数的 '&&'。但是,我仍然不明白是什么让 clang 认为 '&&' 重载是更好的选择。

为什么在双重转换中添加隐式浮点数会影响 clang 中的行为?谁是对的?

【问题讨论】:

    标签: c++ c++11


    【解决方案1】:

    当你用5.5f 调用时,T 是浮点数,Func 调用实际上变成了Func(double(a))。该参数是临时的,因此应选择右值重载。

    当您使用5.5 调用时,T 是双倍的,并且在调用Func(a) 时不会创建临时值。命名变量不能绑定到右值引用,所以左值重载是唯一的选择。

    MSVC 有一个长期存在的错误功能,它允许临时对象绑定到非 const 左值引用。这就是为什么即使在第一种情况下它也错误地选择了左值重载。尝试使用 /Za 进行编译(禁用语言扩展) - 我相信它会匹配 clang 的行为。

    【讨论】:

    • 为什么T = double时没有创建一个临时的?
    • 5.5 inside TFunca,它有一个名字,因此是一个左值。
    • 很遗憾,我目前不在一台装有 VS2013 的机器前,但是 /Za 并不能解决 VS2012 中的问题。
    • 对于那些发现这个 SO Q&A 试图弄清楚为什么他们的右值引用重载没有被调用的其他人,在不同的情况下,并且处理 std::strings 的父亲而不是双打,我能够通过将调用 Func(a); 更改为 Func(std::move(a)); 来“强制”调用右值版本。当然,您的实际里程可能会有所不同。
    猜你喜欢
    • 1970-01-01
    • 2021-10-28
    • 2012-02-07
    • 2019-02-16
    • 1970-01-01
    • 2014-08-30
    • 2019-08-22
    • 2010-09-09
    • 1970-01-01
    相关资源
    最近更新 更多