何时在 constexpr 函数中使用模板非类型 类 或普通参数

when to use template non-type classes or plain arguments in constexpr functions

我很不清楚何时在 constexpr 函数中使用 非类型模板参数 (C++20) 或 普通参数 。我不清楚限制是什么以及何时从纯参数切换到 non-type template parameters(请参阅 Live)。 这里有一个例子说明了 普通参数 :

的笨拙
template<typename Tuple, typename Pred>
constexpr auto getLambda(Tuple&& tuple, Pred&& pred)
{
   return [=](auto I, auto J) {
        return pred(std::get<I>(tuple), std::get<J>(tuple));
   };
}

template<typename T>
struct A
{
    constexpr A(T t) : val(t){};
    T val;
};

int main()
{
    static constexpr auto t = std::make_tuple(A{10.0}, A{1});
    constexpr auto p   = [](auto&& a, auto&& b) { return a.val < b.val; };
    constexpr auto s   = getLambda(t, p);
    //constexpr auto b = s(1,0); // that does unfortunately not compile -> go back write differently... :-|||
}

大多数情况下,我首先尝试使用像上面那样的普通参数,在对 non-constant 表达式的编译错误进行了繁琐的摆弄之后,尝试使用 template<auto t> 的方法(非类型模板参数。主要是然后两个实现一个用于每个用例(这对我来说似乎很愚蠢......)

在我看来,使用 C++20 的现代泛型编程倾向于使用 constexpr 和一些类型元编程进行编译时计算。 谁能阐明这个相当新的 C++ "dark-corner"。我可能误会了 当某事不是 constant-expression 而当它是...

简短版本:使用非类型模板参数来设置非类型模板参数(在任何地方都更通用,你需要 constant expression)和其他一切的普通参数。

关于 constexpr 函数,您始终要牢记的一点是,它们也可以在运行时调用。所以每个普通参数不一定是常量表达式。因此,您不能使用它来提供非类型模板参数(如 std::get<I> 中的 I)。

当然有人会争辩说,当调用计算一个 constexpr 变量时,传递的参数总是常量表达式,并且也可以在函数内部使用。但是,如果 constexpr 函数在编译时工作但在运行时不再工作,那将是意想不到的。

可以预料到新的 consteval keyword in C++20, one could use normal arguments to consteval functions in constant expressions, since we know that these arguments have to be constant expressions. But this does not seem to be the case: https://godbolt.org/z/guz7FQ 为什么会这样,我不知道。但总的来说,我喜欢普通变量和非类型模板参数之间的分离。