I was testing this code (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);
}
};
and I was puzzled for it not working. GCC and clang agree on i
not being a constant expression, so they refuse to let me pass it as a template parameter. However, i
is clearly known at compile-time so, to my limited understanding, the compiler shouldn't have any problem to use it to instantiate the template.
Is there a reason for this not to work? Will it work in the future? I have tested with trunk versions of both compilers, with same result.
It doesn't matter that i
is guaranteed to be evaluated only at compile-time when its value is known in an abstract sense.
It also doesn't matter whether the function is consteval
or constexpr
or none of these.
The language is still statically typed and nth_type_t<i, Ts...>;
must in any given instantiation of the function refer to exactly one type. If i
can change in the for
loop, that is not possible to guarantee.
The language requires that the expression i
when used as template argument is by itself a constant expression, independently of whether the whole function body can only be evaluated as part of a larger constant expression. But i
is neither declared constexpr
, nor declared const
with constant initializer.