我应该避免静态constexpr局部变量吗?如果是,为什么?



考虑如下代码,其中文字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配对时,它是否有任何可观察到的效果?


关于这个被标记为重复的问题,它是关于static constexpr int x [] = {}的,而不是static constexpr int x {}的。这至少突出了这种情况(应用于x指针的属性与应用于*x指针的属性)和我的情况(没有指针)之间的一个区别。


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

标准实际上从未讨论过编译时除了在执行前检查类型和实例化模板之外,什么都没有。这意味着这个程序必须被诊断(而不是"拒绝"!),即使非常量数组长度和模板参数从未被"使用",并且可能被解释器合理地忽略:

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除非对象很大,它的地址不重要(),例如:,用于作为模板参数或通过递归使用)。

相关内容

最新更新