I'm trying to use a consteval function parameter in constexpr context:
consteval auto foo(int size) {
std::array arr; // error: size is not constexpr
auto const_size = std::meta::reflect_constant(size);
auto array_type = std::meta::substitute(^^std::array, {^^int, const_size});
[:array_type:] arr; // error: array_type is not constexpr
// I can even inspect the array type in call foo(10):
// error: uncaught exception ‘&"std::array"[0]’
throw std::meta::display_string_of(array_type).data();
}
I can materialize array with std::meta::reflect_constant_array or std::meta::define_static_array but get my size erased:
consteval auto foo(int size) {
auto helper = std::ranges::views::iota(0, size);
auto arr_refl = std::meta::reflect_constant_array(helper);
auto arr = std::meta::extract(arr_refl);
// I can also inspect the static array in call foo(5):
// error: uncaught exception ‘&"const int [5]{0, 1, 2, 3, 4}"[0]’
throw std::meta::display_string_of(arr_refl).data();
}
Obviously it's easily achieved with non-type template parameters:
template consteval auto foo() { std::array arr; }
Notice that we do get a way of instantiating non-type template parameters with non-constexpr values: the (possible) implementation of std::meta::define_static_array uses extract() to implicitly instantiate template<> __fixed_array with non-constexpr values of r to put them in static storage:
// From P3491R3
template
inline constexpr T __fixed_array[sizeof...(Vs)]{Vs...};
template
consteval auto reflect_constant_array(R&& r) -> info {
auto args = vector{^^ranges::range_value_t};
for (auto&& elem : r) {
args.push_back(reflect_constant(elem));
}
return substitute(^^__fixed_array, args);
}
template
consteval auto define_static_array(R&& r)
-> span const>
{
using T = ranges::range_value_t;
// produce the array (info)
auto array = meta::reflect_constant_array(r);
// turn the array into a span
return span(extract(array), extent(type_of(array)));
}
It seems like the language strongly resists the idea of making function parameters constexpr or reflecting values known to evaluator as constexpr variables. And I don't see exactly why it's disallowed.
Even with static reflections you only get a tiny extract() trick which (despite knowing the exact type from info) requires explicit return template parameter, effectively covering the loophole.