提问人:Jan Schultke 提问时间:6/25/2023 更新时间:6/25/2023 访问量:163
您可以在 constexpr 函数中声明静态局部变量吗?
Can you declare static local variables in a constexpr function?
问:
是否可以在函数中使用局部变量?例如: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);
GCC 12 无法编译此内容,并出现以下错误:
<source>:9:39: error: 'names' defined 'static' in 'constexpr' context
9 | static constexpr std::string_view names[] {
| ^~~~~
其他编译器允许这样做。规则是什么,什么时候允许?
- 我们可以在一般情况下使用吗,或者
static
- 只是 ,或者
static const
- 只?
static constexpr
答:
13赞
Jan Schultke
6/25/2023
#1
自 C++23 以来,此代码是可以的,因为对 的限制已经解除。static constexpr
自 C++23 以来放宽限制
在 C++23 之前,不仅在函数中初始化局部是非法的,而且声明一个也是非法的,即使控制没有流经它。
例如:static
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;
}
禁止变量一直是一个任意的限制,P2647 - 允许在 constexpr 函数中使用静态 constexpr
变量。
static 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; }
很容易看出,在编译时使用时会引入大量问题和疑问,因此它可能永远不会不受限制。它打破了函数是纯函数(没有副作用)的假设,并且还使得记住它们变得不安全(缓存它们的结果以减少调用它们的频率)。static
constexpr
大约static const
static const
也是有问题的,因为它可以初始化为函数参数:
constexpr int remember_first_call(int x) {
static const int y = x;
return y;
}
此函数将始终返回首次调用它的参数,该参数在编译时引入了不应存在的“状态”和“时间”概念。
但是,该规则有一个例外: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;
}
上一个:采访中的共享指针查询 [已关闭]
下一个:模板成员函数不能显式专用
评论