为什么模板参数不被视为常量表达式(对于 consteval)?

问题描述 投票:0回答:1

我想使用 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 函数?谢谢!

c++ c++20
1个回答
0
投票

您的

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;
    }
};

在编译器资源管理器上运行

© www.soinside.com 2019 - 2024. All rights reserved.