【问题标题】:Why is this expression not a constant expression?为什么这个表达式不是常量表达式?
【发布时间】:2017-12-20 15:01:12
【问题描述】:

这段代码中的表达式b应该是一个核心常量表达式

int main()
{
    constexpr int a = 10;
    const int &b = a;
    constexpr int c = b; // here
    return 0;
}

因为标准说(n4700 中的 8.20,第 2 段 [expr.const])

表达式e 是一个核心常量表达式,除非对 e 将评估以下表达式之一:

  • ...

  • 左值到右值的转换 (7.1),除非它应用于

    • ...

    • 非易失性左值,指的是用 constexpr 定义的非易失性对象,或指代此类对象的非可变子对象, 或

首先,上面代码中的表达式b 是一个左值(也是一个左值),因为它是一个引用,因此是一个变量(8.1.4.1,第 1 段) [expr.prim.id.unqual]):

如果实体是函数,则表达式是左值, 变量,或数据成员和纯右值;如果标识符指定位域 (11.5),则它是位域。

其次,变量b表示的对象是a,用constexpr声明。但是,gcc 抱怨

./hello.cpp: In function ‘int main()’:
./hello.cpp:6:20: error: the value of ‘b’ is not usable in a constant expression
  constexpr int c = b;
                    ^
./hello.cpp:5:13: note: ‘b’ was not declared ‘constexpr’
  const int &b = a;

据我所知,引用不是对象,因此上面的项目符号显然表明a 应使用constexpr 声明。我错过了什么吗?我不同意 gcc 的原因是 gcc 将b 视为一个对象,因此需要用constexpr 声明它。但是,b 不是对象!

【问题讨论】:

  • Clang 同意 GCC。但我想我同意你的观点,这是标准或编译器的缺陷。另外值得注意的是,MSVC 接受代码。

标签: c++ language-lawyer c++17


【解决方案1】:

核心常量表达式的规则之一是我们can't evaluate:

一个id-expression,它引用引用类型的变量或数据成员,除非该引用具有前面的初始化并且

  • 用常量表达式初始化或
  • 它的生命周期始于对 e 的评估;

b 是一个id-expression,它引用了一个具有先前初始化的引用类型的变量。但是,它是从a 初始化的。 a 是常量表达式吗?来自[expr.const]/6

常量表达式要么是一个泛左值核心常量表达式,它引用一个作为常量表达式(如下定义)的允许结果的实体,要么是一个纯右值核心常量表达式,其值满足以下约束:[...]

实体是常量表达式的允许结果,如果它是具有静态存储持续时间的对象,要么不是临时对象,要么是其值满足上述约束的临时对象,或者它是一个函数。

a 是一个 glvalue 核心常量表达式(它没有遇到 expr.const/2 中的任何限制),但是它不是一个具有静态存储持续时间的对象。也不是函数。

因此,a 不是常量表达式。因此,b 不是从常量表达式初始化的,因此不能在核心常量表达式中使用。因此c 的初始化格式不正确,因为它不是一个常量表达式。将a声明为static constexpr int,gcc和clang都接受程序。

C++,你这个神奇的野兽。

【讨论】:

  • b 是用一个左值初始化的,而 a 作为一个左值 不是一个常量表达式。
  • 确实,注意 clang 也拒绝编译 "constexpr int const& b = a;"说“对'a'的引用不是一个常量表达式”......
  • 可能是因为a是一个局部变量,所以底层指针会改变?
  • [expr.const]/6: “一个常量表达式是一个泛左值核心常量表达式,它引用一个实体,它是一个常量表达式的允许结果(定义如下),或纯右值核心常量表达式[...]。如果实体是具有静态存储持续时间且不是临时对象或临时对象的对象,则该实体是常量表达式的允许结果其值满足上述约束,或者是一个函数。”
  • @AnT 我不同意。位域要求“整数常量表达式”,它不是“常量表达式”的子集,而是“整数 [...] 类型的表达式,隐式转换为纯右值,其中转换后的表达式是核心常量表达式。”不同的要求。
猜你喜欢
  • 2019-11-13
  • 2014-08-26
  • 1970-01-01
  • 2022-10-08
  • 1970-01-01
  • 2019-06-22
  • 1970-01-01
  • 1970-01-01
  • 2011-11-15
相关资源
最近更新 更多