此程序应该输出0还是1?在我阅读和理解C ++ 14标准中引用的段落时,它应该打印1,但是GCC和clang都打印0(因为推导的类型是A const
而不是A const&
):< / p>
#include <iostream>
struct A {};
int main()
{
A a;
A const& ra = std::move(a); // #1
std::cout << std::is_same<decltype(true ? ra : std::move(a)),
A const&>::value; // Prints 0
}
在这种情况下,ra
是A const
左值,std::move(a)
是A
xvalue,两种类型。根据关于条件运算符(强调我的)的标准,结果应该是lvalue
类型A const
,因此decltype
结果必须是A const&
:
[expr.cond] / 3 否则,如果第二个和第三个操作数具有不同的类型,并且具有(可能是cv-qualified)类 输入,或者如果两者都是相同值类别和相同类型的glvalues,除了cv-qualification, 尝试将每个操作数转换为另一个操作数的类型。确定的过程 是否可以转换T1类型的操作数表达式E1以匹配类型的操作数表达式E2 T2定义如下:
- 如果 E2是左值:如果E1可以隐式转换(第4条),则E1可以转换为匹配E2 输入“左值参考T2”,但在转换过程中,参考必须直接绑定(8.5.3)左值。
[...]
在这种情况下, E2 是ra
,这是一个左值,另一个可以隐含地转换为&#34;左值引用T2&#34; < / strong>,如第// #1
行所示。 &#34;左值对T2&#34; 的引用被翻译为A const&
,因此,std::move(a)
直接绑定到A const
类型的左值,之后转换时,两个操作数具有相同的类型和值类别,因此:
[expr.cond] / 3 如果第二个和第三个操作数是相同值类别且具有相同类型的glvalues,则结果属于该类型和值类别[...]
因此,运算符结果应该是左值,decltype
结果应该是引用,因此程序应该打印1。
答案 0 :(得分:6)
这个问题措辞笨拙。您应该询问表达式true ? ra : std::move(a)
的类型和值类别应该是什么。该问题的答案是A const
类型的prvalue。这随后意味着程序应该打印0,因为我认为每个编译器都正确。
?:
的规则相当复杂。在这种情况下,我们有两个类类型的表达式,我们试图看看是否可以基于有限的规则子集相互转换。
尝试转换ra
→std::move(a)
失败。我们首先尝试使用target type A&&
,它无法直接绑定到ra
。然后我们在(3.3.1)中尝试备份计划,因为这两个表达式具有相同的基础类类型,但是我们的目标表达式至少不像源表达式那样是cv限定的,所以这也失败了。
尝试转换std::move(a)
→ra
失败(3.1)因为我们需要直接绑定到左值(我们可以将rvalue绑定到const左值引用,但是这里我们必需绑定左值)。但是,(3.3.1)备份成功,因为现在目标类型 至少与源代码一样符合cv标准。
因此,我们应用转换并继续,好像第二个操作数是A const
类型的左值,但第三个操作数现在是A const
类型的prvalue(而不是类型{的xvalue {1}})。
(4)失败,因为它们的价值类别不同。
因此,result is a prvalue。由于它们具有相同的类型,the result is of that type:A
。