临时对象最初是const吗?

时间:2019-01-23 20:06:01

标签: c++ const language-lawyer undefined-behavior temporary-objects

此代码是UB吗?

struct A
{
 void nonconst() {}
};

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

换句话说,(临时)对象最初是const吗?我浏览了该标准,但找不到答案,因此希望引用相关部分。

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

2 个答案:

答案 0 :(得分:9)

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

  

否则,如果初始化表达式为

     
      
  • 是右值(但不是位字段)[...]
  •   
     

然后,在第一种情况下的初始值设定项表达式的值,在第二种情况下的转换结果称为转换后的初始值设定项。   如果转换后的初始值设定项是prvalue,则将其类型T4调整为“ cv1 T4”([conv.qual]),并应用临时实现转换([conv.rval])。 >

因此,这意味着将初始化引用A{}的类型prvalue表达式调整为const A

然后[conv.rval]声明:

  

类型T的prvalue可以转换为类型T的xvalue。   此转换将初始化类型T的临时对象([class.temporary])。

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

因此,代码const_cast<A&>(a).nonconst();未定义的行为

答案 1 :(得分:3)

临时类型是您声明时使用的任何类型。

不幸的是,由于Olivtheir answer中指出,参考初始化规则将类型转换为与参考类型匹配,因此在这种情况下a实际上是指const A。基本上在做

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

因为如果您想停止过载集以接受需要的常量prvalue,则实际上可以创建常量prvalue。

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{});的编译。