为什么我们不能在 consteval 函数中使用编译时 'variables' 作为模板参数?

Why can't we use compile-time 'variables' in consteval functions as template parameters?

我正在测试这段代码 (https://godbolt.org/z/fe6hhbeqW)...

// Returns the nth type in a parameter pack of types (ommited for clarity)
//   template <std::size_t N, typename...Ts>
//   nth_type{}

template <typename... Ts>
struct Typelist{
    template <typename T>
    consteval static std::size_t pos() noexcept { 
        for(std::size_t i{}; i < sizeof...(Ts); ++i) {
            using TN = nth_type_t<i, Ts...>;
            if (std::is_same_v<T, TN>) 
                return i;
        }
        return sizeof...(Ts);
    }
};

我对它不起作用感到困惑。 GCC 和 clang 同意 i 不是常量表达式,因此他们拒绝让我将其作为模板参数传递。但是,i 在编译时是明确已知的,因此,据我有限的理解,编译器使用它来实例化模板应该没有任何问题。

这有什么不起作用的原因吗?将来会起作用吗?我已经用两个编译器的主干版本进行了测试,结果相同。

i 保证仅在 compile-time 处求值并不重要,因为它的值在抽象意义上是已知的。

函数是consteval还是constexpr还是none也没有关系。

该语言仍然是静态类型的,nth_type_t<i, Ts...>; 在函数的任何给定实例化中必须仅引用一种类型。如果i可以在for循环中改变,那是无法保证的。

该语言要求表达式 i 在用作模板参数时本身就是一个常量表达式,而与整个函数体是否只能作为更大的常量表达式的一部分进行计算无关。但是 i 既没有声明为 constexpr,也没有用常量初始值设定项声明为 const

虽然这目前不可能像 the other answer 说的那样,但有一个提案可以使这种循环成为可能。 (有人告诉我它甚至打算包含在 C++20 中,但出于某种原因,它在最后一刻被排除在外。)

提案是P1306, currently named ‘Expansion Statements’, and with any luck it should be included in C++23. There is a tracking issue on GitHub;然而,委员会会议记录仅对成员可见。