Jan*_*tke 8 c++ constants constexpr c++23
可以在函数中使用static局部变量吗?constexpr例如:
#include <string_view>
#include <utility>
enum class axis {
x, y, z
};
constexpr std::string_view axis_name(axis a) {
// use static constexpr to avoid putting the table onto the stack
static constexpr std::string_view names[] {
"x", "y", "z"
};
return names[std::to_underlying(a)];
}
constexpr auto x_name = axis_name(axis::x);
Run Code Online (Sandbox Code Playgroud)
GCC 12 无法编译此错误:
<source>:9:39: error: 'names' defined 'static' in 'constexpr' context
9 | static constexpr std::string_view names[] {
| ^~~~~
Run Code Online (Sandbox Code Playgroud)
其他编译器允许它。规则是什么?什么时候允许?
static一般使用,或者static const,或者static constexpr?Jan*_*tke 13
这段代码从 C++23 开始就可以了,因为已经取消了限制static constexpr。
static在 C++23 之前,在函数中初始化局部变量不仅是非法的constexpr,而且声明局部变量也是非法的,即使控制不流经它也是如此。例如:
constexpr void foo() {
if (false) {
// allowed since C++23, otherwise ill-formed
// ok because control never flows through x
static int x;
}
// allowed since C++23, otherwise ill-formed
// ok because static constexpr
static constexpr int y = 0;
}
Run Code Online (Sandbox Code Playgroud)
禁止static constexpr变量一直是一种任意限制,由P2647 - 允许函数static constexpr中的变量constexpr解除。
要使用此功能,您必须使用最新的编译器。截至撰写本文时,这是编译器支持:
| C++23 特性 | 纸 | 海湾合作委员会 | 铛 | MSVC |
|---|---|---|---|---|
允许函数static constexpr中存在变量constexpr |
P2647R1 | 13 | 16 | / |
另请参阅:cppreference 上的 C++23 编译器支持页面
static为什么一般不允许?目前尚不清楚static对象在编译时应如何表现,以及如何在所有编译器中一致地实现这一点。例如,考虑:
constexpr std::size_t get_size() {
static std::size_t s = 0;
// different result each time get_size() is called
return ++s;
}
// what are A and B??? B = 1, and B = 2 are both reasonable
template <std::size_t A = get_size(), B = get_size()>
constexpr std::size_t foo() { return A + B; }
Run Code Online (Sandbox Code Playgroud)
很容易看出,static在编译时使用时会引入大量问题和问题,因此它可能永远不会不受限制。constexpr它打破了函数是纯函数(没有副作用)的假设,并且也使得记忆它们变得不安全(缓存它们的结果以减少调用它们)。
static conststatic const也是有问题的,因为它可以初始化为函数参数:
constexpr int remember_first_call(int x) {
static const int y = x;
return y;
}
Run Code Online (Sandbox Code Playgroud)
该函数将始终返回第一次调用它时使用的参数,这在编译时引入了不应该存在的“状态”和“时间”的概念。然而,该规则有一个例外static const:
constexpr int foo() {
// allowed since C++23
// ok because const integers are implicitly constexpr when possible
static const int x = 3;
return x;
}
Run Code Online (Sandbox Code Playgroud)