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

是否正确地说编译器可以用其值1替换下面的表达式“a->i”,因为…?

  •  11
  • Ayrosa  · 技术社区  · 7 年前

    以下代码在GCC、CLang和VS2017中编译,以及表达式 a->i return 语句被其常量值1替换。说这个有效吗?因为 a 表达式中使用的ODR A->我 ?.

    struct A 
    { 
        static const int i = 1; 
    }; 
    int f() 
    { 
        A *a = nullptr; 
        return a->i;
    }
    

    附言:我相信 表达式中使用的ODR A->我 因为它满足“除非”条件 [basic.def.odr]/4 ,如下:

    变量 x 其名称显示为可能被评估的 表达 ex ODR是否由使用 前任 除非 应用 左值到右值的转换(7.1)到 X 生成常量表达式 (8.6)不援引任何非琐碎的 函数,如果 X 是一个物体, 前任 是表达式的一组潜在结果的元素 e ,其中 左值到右值转换(7.1)应用于 e e 是一个 丢弃的值表达式(8.2)。

    特别是,表达式 ex == a 是表达式的一组潜在结果的元素 e == a->i ,根据 [basic.def.odr]/2 (2.3) ,包含表达式 前任 ,其中lvalue到rvalue转换应用于 e .

    2 回复  |  直到 7 年前
        1
  •  12
  •   T.C. Yksisarvinen    7 年前

    a 是否使用ODR是因为您未通过“除非”的第一部分:

    将左值到右值的转换(7.1)应用于 x 生成不调用任何非平凡函数的常量表达式(8.6)

    将左值转换为右值 不生成常量表达式。

    其余是核心问题 315 232 .


    您的分析有两种额外的方式:

    • “对象表达式”是使用 . form of class member access ,所以你需要重写 a->i 到点形式,即, (*a).i ,在应用[basic.def.odr]/2.3之前。 不是该表达式潜在结果集的成员。
    • 这个项目符号本身是有缺陷的,因为它是用非静态数据成员编写的。对于静态数据成员,潜在结果集实际上应该是命名的静态数据成员-请参见 core issue 2353 如此 不是该表达式潜在结果集的成员。

    [膨胀系数]/2.7:

    一个表达式 e 是一个 核心常量表达式 除非 评估 e 按照抽象机器的规则 计算以下表达式之一:

    • […]
    • 左值到右值的转换,除非将其应用于
      • 整型或枚举型的非易失性glvalue,它引用前面有一个完整的非易失性const对象。 初始化,用常量表达式初始化,或
      • 引用字符串文本的子对象的非易失性glvalue,或
      • 一个非易失性glvalue,它引用用 constexpr 或指的是 这样的物体,或
      • 文本类型的非易失性glvalue,它引用的非易失性对象的生存期从 e ;
    • […]
        2
  •  -2
  •   Robert Andrzejuk    7 年前

    i 是一个 static 该类的成员…您可以访问 静止的 类的成员通过对实例使用常规方法,它们不会绑定到任何实例,因此您不需要取消引用 nullptr 指针(当使用 sizeof 操作员)。您也可以使用简单的

    return A::i;
    

    语句,因为不需要创建实例来访问它。事实上, const 编译器允许将其作为一个常量值进行管理,因此只有在需要使用其地址的情况下(通过 & operator)编译器可以绕过在只读内存中分配它。

    以下样本将探测:

    #include <iostream>
    
    struct A { 
        static const int i = 1; 
    }; 
    
    int main()
    {
        std::cout << ((A*)0)->i << std::endl;
        std::cout << A::i << std::endl;
    }
    

    将打印

    $ a.out
    1
    1
    $ _