【发布时间】:2017-10-01 19:51:15
【问题描述】:
这个程序应该输出 0 还是 1?在我阅读和理解 C++14 标准中引用的段落时,它应该打印 1,但 GCC 和 clang 都打印 0(因为推断的类型是 A const 而不是 A const&):
#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,两者都是类类型。根据关于条件运算符的标准(强调我的),结果应该是A const 类型的lvalue,因此decltype 结果必须是A const&:
[expr.cond]/3 否则,如果第二个和第三个操作数具有不同的类型并且两者都有(可能是 cv 限定的)类 type,或者如果两者都是相同值类别和相同类型(除了 cv 限定)的泛左值,则 尝试将这些操作数中的每一个转换为另一个的类型。确定过程 T1 类型的操作数表达式 E1 是否可以转换为匹配类型为 E2 的操作数表达式 T2定义如下:
——如果 E2 是一个左值:如果 E1 可以隐式转换(第 4 条)到 键入“对 T2 的左值引用”,受制于在转换中引用必须直接绑定 (8.5.3) 到左值。
[...]
本例中,E2为ra,为左值,其他可隐式转换为"lvalue reference to T2",如图线// #1。 "lvalue reference to T2"翻译为A const&,所以std::move(a)直接绑定到一个A const类型的左值,转换后两个操作数的类型和值类别相同,因此:
[expr.cond]/3 如果第二个和第三个操作数是相同值类别的 glvalues 并且具有相同的类型,则结果是该类型和值类别 [...] .
因此,运算符结果应该是左值,decltype 结果应该是引用,因此程序应该打印 1。
【问题讨论】:
-
这可能会影响
std::common_type的行为,不是吗?或者至少是默认实现:en.cppreference.com/w/cpp/types/common_type -
@ChrisBeck 在这种特殊情况下没有,因为模板参数首先被衰减。
-
@Peregring-lk 您应该永远不要修改问题,使其他人的 cmet(或答案)无效。
-
没关系,他应该只提一下编译器在他修改后的问题中做了什么。评论是轻量级的。无效的答案虽然不好,但应该问一个新问题
-
这段代码没有类型推导。通过“推导类型”我猜你实际上是指条件运算符的第二个和第三个操作数的常见类型。
标签: c++ c++14 conditional-operator decltype