This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

4428. Metafunctions should not be defined in terms of constant subexpressions

Section: 21.4.9 [meta.reflection.access.queries], 21.4.18 [meta.reflection.annotation], 21.4.15 [meta.reflection.array] Status: New Submitter: Jonathan Wakely Opened: 2025-10-24 Last modified: 2025-10-24

Priority: Not Prioritized

View all issues with New status.

Discussion:

Addresses US 102-209

"is a constant (sub)expression" is incorrect now that errors are reported via exceptions.

Proposed resolution:

This wording is relative to N5014.

  1. Modify 21.4.9 [meta.reflection.access.queries] as indicated:

    consteval bool has_inaccessible_nonstatic_data_members(info r, access_context ctx);
    

    -5- Returns: true if is_accessible(R, ctx) is false for any R in nonstatic_data_members_of(r, access_context::unchecked()). Otherwise, false.

    -6- Throws: meta::exception unless

    • (6.1) — The evaluation of nonstatic_data_members_of(r, access_context::unchecked()) is a constant subexpression would not exit via an exception and
    • (6.2) — r does not represent a closure type.

    consteval bool has_inaccessible_bases(info r, access_context ctx);
    

    -5- Returns: true if is_accessible(R, ctx) is false for any R in bases_of(r, access_context::unchecked()). Otherwise, false.

    -6- Throws: meta::exception unless The evaluation of bases_of(r, access_context::unchecked()) is a constant subexpression would not exit via an exception.

  2. Modify 21.4.18 [meta.reflection.annotation] as indicated:

    consteval vector<info> annotations_of_with_type(info item, info type);
    

    -4- Returns: A vector containing each element e of annotations_of(item) where remove_const(type_of(e)) == remove_const(type) is true, preserving their order.

    -5- Throws: meta::exception unless

    • (5.1) — The evaluation of annotations_of(item) is a constant subexpression would not exit via an exception and
    • (5.2) — dealias(type) represents a type that is complete from some point in the evaluation context.

  3. Modify 21.4.18 [meta.reflection.annotation] as indicated:

    template<ranges::input_range R>
      consteval info reflect_constant_array(R&& r);
    

    -8- Let T be ranges::range_value_t<R>.

    -9- Mandates: T is a structural type (13.2 [temp.param]), is_constructible_v<T, ranges::range_reference_t<R>> is true, and is_copy_constructible_v<T> is true.

    -10- Let V be the pack of values of type info of the same size as r, where the ith element is reflect_constant(ei), where ei is the ith element of r.

    -11- Let P be

    • (11.1) — If sizeof...(V) > 0 is true, then the template parameter object (13.2 [temp.param]) of type const T[sizeof...(V)] initialized with {[:V:]...}.
    • (11.2) — Otherwise, the template parameter object of type array<T, 0> initialized with {}.

    -12- Returns: ^^P.

    -13- Throws: meta::exception unless The evaluation of reflect_constant(e) is a constant subexpression would not exit via an exception for every element e of r.