I would like to use consteval functions to perform computations on template parameters at compile time, so that my operations result in immediates that don’t incur any performance penalty. For example:
// 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.
}
};
I used consteval so that abs(N) would be replaced with an immediate value rather than calling the function at runtime (as would happen if abs() were constexpr). For example, within the body of Test<7>::isValid(), I would think abs(7) resolves to 7 and does not need to be calculated at runtime. However, this code produces the following error: Call to consteval function 'abs' is not a constant expression ... subexpression not valid in a constant expression [invalid_consteval_call]
(tested in clang 17.0.6). This error still occurs if you attempt to define a static constexpr variable based on N:
// 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;
}
};
The funny part is, if you change abs() from consteval to constexpr in this version, then the generated code uses an immediate like I wanted! On the other hand, templates can be used with consteval to achieve the same goal:
template <int X>
consteval int abs() {
return X < 0 ? -X : X;
}
template <int N>
struct Test {
bool isValid(int y) {
return y < abs<N>();
}
}
I also noticed that using a static constexpr variable instead of a template parameter works, although here it’s pretty easy to see why:
struct Test {
static constexpr int N = 7;
bool isValid(int y) {
return y < abs(N);
}
}
Why are template parameters not allowed to be passed to consteval functions? Thanks!