我想使用 consteval 函数在编译时对模板参数执行计算,这样我的操作就不会产生任何性能损失。例如:
// Changing this to constexpr will cause the function
// to be invoked at runtime.
consteval int abs(int x) {
return x < 0 ? -x : x;
}
template <int N>
struct Test {
bool isValid(int y) {
return y < abs(N); // Error.
}
};
我使用了 consteval,以便将 abs(N) 替换为立即值,而不是在运行时调用该函数(如果 abs() 是 constexpr,则会发生这种情况)。例如,在 Test<7>::isValid() 的主体中,我认为 abs(7) 解析为 7 并且不需要在运行时计算。但是,此代码会产生以下错误:
Call to consteval function 'abs' is not a constant expression ... subexpression not valid in a constant expression [invalid_consteval_call]
(在 clang 17.0.6 中测试)。如果您尝试基于 N 定义静态 constexpr 变量,仍然会发生此错误:
// Changing this to constexpr works though!
consteval int abs(int x) {
return x < 0 ? -x : x;
}
template <int N>
struct Test {
static constexpr int ABS_N = abs(N); // Error
bool isValid(int y) {
return y < ABS_N;
}
};
有趣的是,如果你在this版本中将abs()从consteval更改为constexpr,那么生成的代码将使用我想要的立即数!另一方面,模板可以与 consteval 一起使用来实现相同的目标:
template <int X>
consteval int abs() {
return X < 0 ? -X : X;
}
template <int N>
struct Test {
bool isValid(int y) {
return y < abs<N>();
}
}
我还注意到使用静态 constexpr 变量而不是模板参数是可行的,尽管在这里很容易看出原因:
struct Test {
static constexpr int N = 7;
bool isValid(int y) {
return y < abs(N);
}
}
为什么不允许将模板参数传递给 consteval 函数?谢谢!
您的
consteval
函数具有未定义的行为,当且仅当 x
是 INT_MIN
(又名:std::numeric_limits<int>::min()
)。#include <limits>
consteval int abs(const int x) {
if (x == std::numeric_limits<int>::min())
return std::numeric_limits<int>::max();
return x < 0 ? -x : x;
}
仅凭这一更改,我无法在 clang 上复制您的错误(x64 上的 trunk = 18.1.0)。
但是,您的
isValid()
方法可能应该是 static
,或者至少是 const
。即:
#include <limits>
consteval int abs(const int x) {
if (x == std::numeric_limits<int>::min())
return std::numeric_limits<int>::max();
return x < 0 ? -x : x;
}
template <int N>
struct Test {
static constexpr int ABS_N = abs(N); // Should be fine.
static constexpr bool isValid(const int y) noexcept {
return y < ABS_N;
}
};