【问题标题】:Should I avoid static constexpr local variables? If so, why?我应该避免使用静态 constexpr 局部变量吗?如果是这样,为什么?
【发布时间】:2021-11-06 18:26:20
【问题描述】:

考虑如下代码,其中 literal some_magic_int(例如 3)被命名只是为了更清楚它代表什么常量:

void f() {
    static constexpr int this_variable{some_magic_int};
    do_something_with(this_variable);
}
int main() {
    // ...
    f();
    // ...
}

我很确定 constexpr 必须在这里:some_magic_int 是字面意思,所以它永远不会改变,我给它起一个名字只是为了清楚起见,而不是为了改变它,所以它至少应为const;那么为什么不在constexpr 在编译时拥有它呢?

但是static 呢?这只是不必要的吗?还是有害?如果是这样,为什么?另外,在局部变量的声明中与constexpr 配对时,它是否有任何可观察到的效果?


关于question to which this is marked as duplicate of,大约是static constexpr int x [] = {},而不是static constexpr int x {}。这突出了该案例(应用于x 指针的属性与应用于*x 指针的属性)和我的案例(没有指针)之间的至少一个区别。


此外,一旦我将constexpr 添加到局部变量的说明符(这是有意义的,例如添加到int),我就是说该变量是编译时已知的。为什么这并不意味着不需要任何运行时实体?

【问题讨论】:

  • 这能回答你的问题吗? stackoverflow.com/questions/13865842/…。 TLDR:简短的回答是,静态不仅有用,而且总是很受欢迎
  • 您还可以看到组装的差异 - godbolt。非静态实际上存储在堆栈中,static 是程序范围的。
  • @PKramer 我不明白为什么必须静态存储普通的intconstexpr to name 的主要观点不是一个神奇的数字(当然,这是一种很好的风格)?尽管如此,如果它是一个本地的,很有可能在生成的代码中内联而不是在任何地方消耗存储,我不会有任何问题。如果它是 ints 的数组或字符串文字,那将是另一个故事......
  • 我相信这个问题与重复的主题不同,因为answer 没有详细说明static constexpr 整数,而是关注static constexpr 整数数组。应该是不同的主题。
  • @LouisGo 这是不正确的。尽管可以进行优化,但不能保证这一点。 local static 定义初始化时间,没有它 this_variable 是 constexpr 值,而 &this_variable 不是。如果它是静态的,&this_variable 是一个 constexpr 值,因为该对象具有进程范围的生命周期。

标签: c++ static c++17 constexpr local-variables


【解决方案1】:

该标准实际上并没有谈论 compile-time 任何东西,只是说在执行之前检查类型并实例化模板。这意味着这个程序必须被诊断(而不是“拒绝”!),即使非常量数组长度和模板参数从未被“使用”并且可能被解释器合理地忽略:

template<int> void f() {}
int main(int argc,char **argv) {
  if(false) {
    int buf[argc];  // accepted by a common extension
    f<argc>();
  }
}

除此之外,语义是每次评估都是程序普通执行的一部分,而常量折叠就像其他任何优化一样只是一种优化。 (毕竟,我们可以优化argc*2*3*4,即使它不包含可能是常量表达式的非文字子表达式。)对于常量表达式,这在很大程度上是不可观察,因为常量评估不会产生副作用(这也避免了常量初始化的非块变量之间的交互)。但是,它可以通过局部变量的 地址 产生影响:

bool introspect(const int *p=nullptr) {
  constexpr int x=0;
  return p ? p==&x : introspect(&x);  // always false
}

如果这些变量的地址转义,编译器必须使这些变量占用内存,这是对先前标记的重复项的答案的大部分内容。因此,首选 static 是有意义的,除非对象很大并且它的地址无关紧要(例如,用作模板参数或通过递归) .

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-24
    • 1970-01-01
    • 2012-02-25
    • 2013-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-10
    相关资源
    最近更新 更多