临时对象最初是 const 吗?

Is temporary object originally const?

这个代码是UB吗?

struct A
{
 void nonconst() {}
};

const A& a = A{};
const_cast<A&>(a).nonconst();

换句话说,(临时)对象原来是const?我已经查看了标准,但找不到答案,因此希望能引用相关部分。

编辑: 对于那些说 A{} 不是 const 的人,那么你可以做 A{}.nonconst() ?

临时文件的类型是你声明它的任何类型。

不幸的是,由于 Oliv points out in 引用初始化规则转换类型以匹配引用类型,因此在这种情况下 a 实际上指的是 const A。基本上是在做

using const_A = const A;
const A& a = const_A{};

因为如果您想阻止重载集接受您需要的常量纯右值,您实际上可以创建常量纯右值

ret_type function_name(some_type const&&) = delete;

否则如果你有

ret_type function_name(some_type const&)

在重载中设置它然后常量 prvalue 将绑定到它,如果你只删除了

ret_type function_name(some_type&&)

代替。你可以看到这个与

一起工作
struct bar{};

void foo(bar const&) { std::cout << "void foo(bar const&)\n"; }
void foo(bar&&) =delete;

using c_bar = const bar;

int main()
{   
    foo(c_bar{});
}

此处,void foo(bar const&) 被调用,因为 c_bar{} 实际上是 const,而不是如果您使用了 foo(bar{});,则会出现已删除的函数错误。添加

void foo(bar const&&) = delete;

需要实际停止 foo(c_bar{}); 编译。

引用a的初始化由[dcl.init.ref]/5给出(大胆的矿):

Otherwise, if the initializer expression

  • is an rvalue (but not a bit-field)[...]

then the value of the initializer expression in the first case and the result of the conversion in the second case is called the converted initializer. If the converted initializer is a prvalue, its type T4 is adjusted to type “cv1 T4” ([conv.qual]) and the temporary materialization conversion ([conv.rval]) is applied.

所以表示初始化引用的类型纯右值表达式A{}调整为const A.

然后 [conv.rval] 状态:

A prvalue of type T can be converted to an xvalue of type T. This conversion initializes a temporary object ([class.temporary]) of type T.

因此绑定到引用的临时对象的类型与调整后的 prvalue 类型相同:const A.

所以代码const_cast<A&>(a).nonconst();未定义的行为