具有相同底层类类型的条件运算符

时间:2017-10-01 19:51:16

标签: c++ c++14 conditional-operator decltype

此程序应该输出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
}

在这种情况下,raA 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。

1 个答案:

答案 0 :(得分:6)

这个问题措辞笨拙。您应该询问表达式true ? ra : std::move(a)的类型和值类别应该是什么。该问题的答案是A const类型的prvalue。这随后意味着程序应该打印0,因为我认为每个编译器都正确。

?:的规则相当复杂。在这种情况下,我们有两个类类型的表达式,我们试图看看是否可以基于有限的规则子集相互转换。

尝试转换rastd::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 typeA