Using a consteval function parameter in constexpr context [duplicate]

11 hours ago 1
ARTICLE AD BOX

The key point is:

consteval

means the function call is evaluated at compile time.

It does not mean that function parameters become constant expressions.

So inside:

consteval auto foo(int size) { std::array<int, size> arr; }

size is still an ordinary function parameter. It is known to the constant evaluator during this particular invocation, but the C++ type system does not treat it as a constant expression usable in template arguments. That is why std::array<int, size> is ill-formed.

This is intentional. std::array<int, size> changes the type of a local variable depending on a function parameter. But normal functions, including consteval functions, are not instantiated separately per argument value. Templates are.

That is why this works:

template<int S> consteval auto foo() { std::array<int, S> arr; }

Here S is not a function parameter. It is a non-type template parameter, so it is part of the function specialization’s type-level identity.

Reflection does not fully change that rule. std::meta::substitute can produce a reflection of std::array<int, 10>, and reflect_constant(size) can reflect a value in some contexts, but splicing a reflected type back into code still requires the reflection value itself to be usable where the language expects a constant expression. P2996 is the current reflection proposal, and P3491/P3617 provide library facilities such as define_static_array / reflect_constant_array, but these are library escape hatches, not general “constexpr function parameters.”

So this:

auto array_type = std::meta::substitute(^^std::array, {^^int, const_size}); [:array_type:] arr;

fails for the same basic reason: array_type is a local variable, not a compile-time template parameter or a constant expression object usable by the splice.

define_static_array works because it materializes a static object through a template-like mechanism. It does not make the original parameter size a type-level constant. It creates a static entity and gives you a pointer/span/reference-like way to access it. That is why the “size” feels erased unless you separately recover it from the reflected type or pass the expected type to extract.

So the short answer is:

conseval evaluation-time knowledge ≠ constant-expression/type-level value

If you need size to affect a type, use a template parameter:

template<int S> consteval auto foo() { std::array<int, S> arr; }

If you only need storage/data, use reflection/static-object facilities such as define_static_array, but that is intentionally not the same as turning a function parameter into an NTTP.

Read Entire Article