非 constexpr 变量有时可用于 constexpr 上下文?

Non-constexpr variable sometimes usable in a constexpr context?

看看下面的代码示例:

template<bool val>
struct test {
    static const int value_a = val;
    const int value_b = val;
    constexpr int get_value_a() const noexcept { return value_a; }
    constexpr int get_value_b() const noexcept { return value_b; }
};


int main(int argc, char** argv) {
    auto t = test<true>{};
    static_assert(t.value_a);
    // static_assert(t.value_b);
    static_assert(t.get_value_a());
    // static_assert(t.get_value_b());
}

gcc 和 clang 都同意这应该编译,但包括任何注释掉的静态断言会使它无效。例如,gcc 然后会产生这些错误消息:

error: non-constant condition for static assertion

error: the value of ‘t’ is not usable in a constant expression

note: ‘t’ was not declared ‘constexpr’

这对我来说非常有意义,也正是我所想的。但我真的不知道为什么其他两个静态断言首先编译。允许这样做的标准中的相关段落是什么?

具体来说,这是如何形式化的?仅使用变量与实际访问其运行时值(这将是 constexpr 上下文中唯一被禁止的事情)之间是否存在明确定义的区别?

这只是规则。在 constexpr 之前,const 用常量表达式初始化的变量本身可以用作常量表达式(也为了与 C 的某些兼容性)

从标准[expr.const]/3:

A variable is usable in constant expressions after its initializing declaration is encountered if [...] it is a constant-initialized variable [...] of const-qualified integral or enumeration type.

这不会扩展到 const auto t = test<true>{},因为 test<true> 不是整数类型(您需要 constexpr auto t = test<true>{},正如预期的那样,遵循其余部分的规则款)

无法在编译时计算 value_b 的地址。

只能将静态数据成员声明为constexpr

相关:Why can't non-static data members be constexpr?

In particular, how is this formalized?

http://eel.is/c++draft/expr.const#4.1

An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following:

this ([expr.prim.this]), except in a constexpr function ([dcl.constexpr]) that is being evaluated as part of e;

访问非静态成员计算 this 指针。访问静态成员不会。