Question Details

No question body available.

Tags

c++ reflection constexpr consteval c++26

Answers (1)

May 8, 2026 Score: 5 Rep: 51 Quality: Medium Completeness: 60%

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 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 is ill-formed.

This is intentional. std::array 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
consteval auto foo() {
    std::array 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, and reflectconstant(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 definestaticarray / reflectconstantarray, but these are library escape hatches, not general “constexpr function parameters.”

So this:

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

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

definestaticarray 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
consteval auto foo() {
    std::array arr;
}

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