作为对another question的回答,我想发布以下代码(也就是说,我想根据这个想法发布代码):
#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
}
然而,虽然MSVC 11.0在最后一次调用时会窒息,但正如IHMO应该的那样,MinGW g ++ 4.7.1只接受它,并使用rvalue reference formal参数调用构造函数。
它看起来像,好像左值被绑定到右值引用。一个滑稽的答案可能是左值转换为右值。但问题是,这是一个编译器错误,如果不是,那么神圣标准是如何允许的呢?
编辑:我设法将其全部缩减为以下非常简短的示例:
void foo( double&& ) {}
int main()
{
char ch = '!';
foo( ch );
}
无法使用MSVC 11.0编译,使用MinGW 4.7.1进行编译,这是对的吗?
答案 0 :(得分:2)
我没有查看规范,但我猜char
可以自动转换为int
。由于您无法分配任何内容(它是r值),因此R值将传递给类型为int
的临时变量(更明确地为(int)c
值)。
答案 1 :(得分:2)
我发现N3290(与C ++ 11标准相同)包含将double&&
绑定到从int
左值生成的右值的非规范性示例,以及§8.5中更新的措辞。 3 强>
据报道,这些规则旨在避免低效的额外复制。虽然我没有看到如何无法优化这种复制。无论如何,理由是否合理 - 它肯定不会似乎作为合理的效果! - 允许使用以下代码,并使用MSVC 11和MinGW g ++ 4.7进行编译:“如果T1与T2有参考关系且参考是右值参考, 初始化表达式不应该是左值。“
struct Foo {};
struct Bar { Bar( Foo ) {} };
void ugh( Bar&& ) {}
int main()
{
Foo o;
ugh( o );
}
显然MSVC 11在不允许左值时是错误的 - &gt;右值转换。
<小时/> 编辑:我了解到有关此问题的缺陷报告DR 1414。 2012年2月的结论是,当前的行为规范是“正确的”,可能与它反映意图的程度有关。然而据报道,委员会仍在讨论这个问题,大概是关于意图的实用性。
答案 2 :(得分:0)
大概你同意这是有效的吗?
void foo( double ) {} // pass-by-value
int main()
{
char ch = '!';
foo( ch );
}
从char
到double
的隐式转换,因此该功能可行。
在您编辑的问题的示例中,它是相同的,有一个隐式转换产生一个临时(即一个右值),而rvalue-reference参数绑定到该临时值。如果您愿意,可以明确转换:
void foo( double&& ) {} // pass-by-reference
int main()
{
char ch = '!';
foo( double(ch) );
}
但在这种情况下,这并没有真正改变任何事情。如果double
- &gt;那将是必要的。 char
只能明确转换(例如,对于具有显式构造函数或显式转换运算符的类类型),但double
到char
是有效的隐式转换。
“rvalue-reference无法绑定到左值”规则,您正在考虑将T&&
绑定到T
左值,并且该规则不会被破坏,因为{{ 1}}不绑定到double&&
,它绑定到由隐式转换创建的临时值。
该规则不仅用于防止不必要的额外复制,而且用于修复先前规则中存在的真正安全问题,请参阅http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2812.html
编辑:有人询问委员会反对者是否需要这种行为(请参阅DR 1414),并且确定是,这种行为是有意的并且是正确的。用于达到该位置的一个论点是,使用当前规则,此代码更有效:
char
使用当前规则,通过隐式转换创建临时std::vector<std::string> v;
v.push_back("text");
,然后调用std::string
,并将临时移动到向量中。如果std::vector<T>::push_back(T&&)
重载对转换结果不可行,那么上面的代码会调用push_back
,这将导致副本。当前的规则使这个真实世界的用例更有效。如果规则说rvalue-refs无法绑定到隐式转换的结果,则必须更改上面的代码以获得移动的效率:
std::vector<T>::push_back(const T&)
恕我直言,当构造函数不明确时,必须显式构造v.push_back( std::string{"text"} );
是没有意义的。我希望显式/隐式构造函数具有一致的行为,我希望第一个std::string
示例更有效。