将左值绑定到右值参考 - g ++ bug?

Che*_*Alf 10 c++ compiler-errors

作为另一个问题的答案,我想发布以下代码(也就是说,我想根据这个想法发布代码):

#include <iostream>
#include <utility>      // std::is_same, std::enable_if
using namespace std;

template< class Type >
struct Boxed
{
    Type value;

    template< class Arg >
    Boxed(
        Arg const& v,
        typename enable_if< is_same< Type, Arg >::value, Arg >::type* = 0
        )
        : value( v )
    {
        wcout << "Generic!" << endl;
    }

    Boxed( Type&& v ): value( move( v ) )
    {
        wcout << "Rvalue!" << endl;
    }
};

void function( Boxed< int > v ) {}

int main()
{
    int i = 5;
    function( i );  //<- this is acceptable

    char c = 'a';
    function( c );  //<- I would NOT like this to compile
}
Run Code Online (Sandbox Code Playgroud)

然而,虽然MSVC 11.0在最后一次通话扼流圈,因为它IHMO应MinGW的G ++ 4.7.1只是被动地接受它,并调用与右值引用形参的构造函数.

看起来好像左值被绑定到右值引用.一个滑稽的答案可能是左值转换为右值.但问题是,这是一个编译器错误,如果不是,那么神圣标准是如何允许的呢?


编辑:我设法将它全部减少到以下非常短的例子:

void foo( double&& ) {}

int main()
{
    char ch = '!';
    foo( ch );
}
Run Code Online (Sandbox Code Playgroud)

无法用MSVC 11.0编译,用MinGW 4.7.1编译,这是对的吗?

Jon*_*ely 0

想必您同意这是有效的?

void foo( double ) {}  // pass-by-value

int main()
{
    char ch = '!';
    foo( ch );
}
Run Code Online (Sandbox Code Playgroud)

有一个从charto 的隐式转换double,因此该函数是可行的。

在您编辑的问题的示例中也是如此,有一个隐式转换会生成一个临时值(即右值),并且右值引用参数绑定到该临时值。如果您愿意,可以显式进行该转换:

void foo( double&& ) {}  // pass-by-reference

int main()
{
    char ch = '!';
    foo( double(ch) );
}
Run Code Online (Sandbox Code Playgroud)

但这并没有真正改变任何事情。double如果->char只能显式转换(例如,对于具有显式构造函数或显式转换运算符的类类型),但doubletochar是有效的隐式转换,则这是必要的。

您正在考虑的“右值引用不能绑定到左值”规则是指将 a 绑定T&&T左值,并且该规则没有被破坏,因为double&&不绑定到char,它绑定到由隐式转换。

该规则的存在不仅是为了防止不必要的额外复制,也是为了解决以前规则中存在的真正安全问题,请参阅http://www.open-std.org/JTC1/SC22/WG21/docs/papers/ 2008/n2812.html

编辑:有人询问这种行为在委员会反射器上是否可取(参见DR 1414),并决定是的,这种行为是有意的并且是正确的。用于达到这一立场的论点之一是,该代码在当前规则下更有效:

std::vector<std::string> v;
v.push_back("text");
Run Code Online (Sandbox Code Playgroud)

根据当前规则,std::string通过隐式转换创建临时值,然后 std::vector<T>::push_back(T&&)调用临时值,并将临时值移动到向量中。如果该push_back重载对于转换结果不可行,则上面的代码将调用std::vector<T>::push_back(const T&),这将导致复制。当前的规则使这个现实世界的用例更加高效。如果规则规定 rvalue-refs 无法绑定到隐式转换的结果,则必须更改上面的代码才能获得移动的效率:

v.push_back( std::string{"text"} );
Run Code Online (Sandbox Code Playgroud)

恕我直言,std::string当构造函数不显式时,必须显式构造 a 是没有意义的。我希望显式/隐式构造函数具有一致的行为,并且我希望第一个push_back示例更加高效。