代码之家  ›  专栏  ›  技术社区  ›  PoweredByRice

临时对象最初是常量吗?

  •  8
  • PoweredByRice  · 技术社区  · 6 年前

    这是UB代码吗?

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

    换句话说,是(临时)对象 const ?我已经看过了标准,但找不到答案,所以希望对相关章节进行报价。

    编辑: 对于那些说 A{} 不是 康斯特 ,那你能吗 A{}.nonconst() ?

    2 回复  |  直到 6 年前
        1
  •  6
  •   Oliv    6 年前

    引用的初始化 a 是由 [dcl.init.ref]/5 (大胆地雷):

    否则,如果初始值设定项表达式

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

    然后,第一种情况下的初始值设定项表达式的值和第二种情况下的转换结果称为已转换的初始值设定项。 如果转换的初始值设定项是prvalue,则将其类型t4调整为类型__cv1 t4_([conv.qual]) 并应用临时物化转换([conv.rval])。

    所以它意味着初始化引用的类型prvalue表达式, A{} ,调整为 const A .

    然后 [conv.rval] 国家:

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

    因此,绑定到引用的临时对象的类型与调整后的 prvalue 类型: 常数A .

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

        2
  •  2
  •   NathanOliver    6 年前

    临时的类型是用什么类型声明的。

    不幸的是, Oliv 指出在 their answer 引用初始化规则将类型转换为与引用类型匹配,因此在本例中 a 实际上是指 const A . 基本上是这样的

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

    因为如果您想阻止重载集接受所需的常量prvalue,实际上可以创建常量prvalues。

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