Title
{can_}substitute specification is ill-formed
Status
wp
Section
[meta.reflection.substitute]
Submitter
Matthias Wippich

Created on 2025-08-15.00:00:00 last changed 1 month ago

Messages

Date: 2025-11-11.10:48:55

Proposed resolution:

This wording is relative to N5014.

  1. Modify [meta.reflection.substitute] as indicated:

    -1- Let TARG-SPLICE(x) be:

    • -1.1- template [: x :] if `is_template(x)` is `true`, otherwise
    • -1.2- typename [: x :] if `is_type(x)` is `true`, otherwise
    • -1.3- ([: x :])

    template<reflection_range R = initializer_list<info>>
      consteval bool can_substitute(info templ, R&& arguments);
    

    -1- Let `Z` be the template represented by `templ` and let `Args...` be a sequence of prvalue constant expressions that compute the reflections held by the elements of `arguments`, in order.

    -2- Returns: `true` if Z<TARG-SPLICE([:Args:])...> is a valid template-id ([temp.names]) that does not name a function whose type contains an undeduced placeholder type. Otherwise, `false`.

    -3- Throws: `meta::exception` unless `templ` represents a template, and every reflection in `arguments` represents a construct usable as a template argument ([temp.arg]).

    -4- [Note: If forming Z<TARG-SPLICE([:Args:])...> leads to a failure outside of the immediate context, the program is ill-formed. — end note]

    template<reflection_range R = initializer_list<info>>
      consteval info substitute(info templ, R&& arguments);
    

    -5- Let `Z` be the template represented by `templ` and let `Args...` be a sequence of prvalue constant expressions that compute the reflections held by the elements of `arguments`, in order.

    -6- Returns: Z<TARG-SPLICE([:Args:])...>.

    -7- Throws: `meta::exception` unless `can_substitute(templ, arguments)` is `true`.

    -8- [Note: If forming Z<TARG-SPLICE([:Args:])...> leads to a failure outside of the immediate context, the program is ill-formed. — end note]

Date: 2025-11-11.10:48:55

[ Kona 2025-11-08; Status changed: Immediate → WP. ]

Date: 2025-11-05.21:01:40

[ Kona 2025-11-05; approved by LWG. Status changed: New → Immediate. ]

Date: 2025-11-15.00:00:00

[ 2025-11-03; Tomasz provides wording. ]

Date: 2025-10-15.00:00:00

[ 2025-10-27; Reflector comments. ]

We lost definition of `Z`. Use TARG-SPLICE([:Args:])....

Date: 2025-10-15.00:00:00

[ 2025-10-27; Tomasz provides wording. ]

This wording is relative to N5014.

  1. Modify [meta.reflection.substitute] as indicated:

    -1- For value `x` of type `info`, and prvalue constant expression `X` that computes the reflection held by `x`, let TARG-SPLICE(x) be:

    • -1.1- template [: X :] if `is_template(x)` is `true`, otherwise
    • -1.2- typename [: X :] if `is_type(x)` is `true`, otherwise
    • -1.3- ([: X :])

    template<reflection_range R = initializer_list<info>>
      consteval bool can_substitute(info templ, R&& arguments);
    

    -1- Let `Z` be the template represented by `templ` and let `Args...` be a sequence of prvalue constant expressions that compute the reflections held by the elements of `arguments`, in order. Let n be the number of elements in `arguments`, and ei be the ith element of `arguments`.

    -2- Returns: `true` if Z<[:Args:]...TARG-SPLICE(e0), ..., TARG-SPLICE(en-1)> is a valid template-id ([temp.names]) that does not name a function whose type contains an undeduced placeholder type. Otherwise, `false`.

    -3- Throws: `meta::exception` unless `templ` represents a template, and every reflection in `arguments` represents a construct usable as a template argument ([temp.arg]).

    -4- [Note: If forming Z<[:Args:]...TARG-SPLICE(e0), ..., TARG-SPLICE(en-1)> leads to a failure outside of the immediate context, the program is ill-formed. — end note]

    template<reflection_range R = initializer_list<info>>
      consteval info substitute(info templ, R&& arguments);
    

    -5- Let `Z` be the template represented by `templ` and let `Args...` be a sequence of prvalue constant expressions that compute the reflections held by the elements of `arguments`, in order. Let n be the number of elements in `arguments`, and ei be the ith element of `arguments`.

    -6- Returns: ^^Z<[:Args:]...TARG-SPLICE(e0) ..., TARG-SPLICE(en-1)>.

    -7- Throws: `meta::exception` unless `can_substitute(templ, arguments)` is `true`.

    -8- [Note: If forming Z<[:Args:]...TARG-SPLICE(e0), ..., TARG-SPLICE(en-1)> leads to a failure outside of the immediate context, the program is ill-formed. — end note]

Date: 2025-10-15.00:00:00

[ 2025-10-22; Reflector poll. ]

Set priority to 1 after reflector poll.

Date: 2025-10-27.16:17:32
Addresses US 114-175

`can_substitute` and `substitute` are currently specified in terms of splices in a template argument list:

[meta.reflection.substitute] p3:

Returns: `true` if Z<[:Args:]...> is a valid template-id ([temp.names]) that does not name a function whose type contains an undeduced placeholder type. Otherwise, `false`.

[meta.reflection.substitute] p7:

Returns: ^^Z<[:Args:]...>.

This wording was introduced in P2996R11. However, merging in changes from P3687 "Final Adjustments to C++26 Reflection" in P2996R13 changed the rules for splices in this context. This makes `can_substitute` and `substitute` as specified currently ill-formed. We cannot use the given syntax to splice an arbitrary choice of values, types and templates anymore.

While the intent seems clear, this should be rephrased to be more technically correct.

History
Date User Action Args
2025-11-11 10:48:55adminsetmessages: + msg15672
2025-11-11 10:48:55adminsetstatus: immediate -> wp
2025-11-05 21:01:40adminsetmessages: + msg15530
2025-11-05 21:01:40adminsetstatus: new -> immediate
2025-11-04 01:08:04adminsetmessages: + msg15485
2025-11-04 01:08:04adminsetmessages: + msg15484
2025-10-27 17:09:42adminsetmessages: + msg15470
2025-10-27 09:58:11adminsetmessages: + msg15436
2025-10-22 13:00:33adminsetmessages: + msg15352
2025-08-15 00:00:00admincreate