非constexpr变量有时可在constexpr上下文中使用吗?

时间:2020-01-26 00:34:42

标签: c++ compilation c++17 constexpr compile-time

看看下面的代码示例:

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然后会产生以下错误消息:

错误:静态声明的非恒定条件

错误:常量表达式不能使用't'值

注意:“ t”未声明为“ constexpr”

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

尤其是这是如何形式化的?仅使用变量与实际访问其运行时值(这将是constexpr上下文中唯一被禁止的东西)之间是否有明确定义的区别?

3 个答案:

答案 0 :(得分:1)

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

根据标准[expr.const]/3

如果变量是常量限定的整数或枚举类型的常量初始化变量,则遇到初始化声明后,该变量即可在常量表达式中使用。

这不会扩展到const auto t = test<true>{},因为test<true>不是整数类型(按照预期,您需要拥有constexpr auto t = test<true>{},遵循该段其余部分的规则)

答案 1 :(得分:1)

尤其是这是如何形式化的?

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

表达式e是核心常量表达式,除非按照抽象机([intro.execution])的规则对e求值将对以下值之一进行求值:

this([expr.prim.this]),但作为e的一部分的constexpr函数([dcl.constexpr])除外;

对非静态成员的访问将评估this指针。不能访问静态成员。

答案 2 :(得分:0)

value_b的地址无法在编译时求值。

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

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