Skip to content

CWG3099 [temp.inst] Instantiation of type aliases from alias templates unspecified #782

Description

@hubert-reinterpretcast

Full name of submitter (unless configured in github; will be published with the issue): Hubert Tong

Reference (section label): [temp.alias], [temp.inst]

Link to reflector thread (if any): N/A

Issue description:

P2996 added the idea that a type alias can result from instantiation of an alias template; however, the timing of the instantiation (and its relation to the immediate context) is unspecified.

Some thoughts:

  • The "traditional" expansion of alias templates are in the immediate context, but the instantiation of class and function templates are not.
  • Unlike classes and functions, it is not possible to declare a type alias without defining it (which may motivate "immediate" instantiation; which, in turn, reduces friction for an "immediate context" treatment).

Consider https://godbolt.org/z/Wof7fcr3a:

#include <meta>

using namespace std::meta;

template <typename T> using A = T *;

template <auto> struct Sink;

template <typename T> void f(Sink<^^A<T> > * = 0); // immediately instantiated and considered as part of the immediate context?
template <typename T> void f(int = 0);
void g() { f<int &>(); }

constexpr auto x = substitute(^^A, {^^int &});  // valid until dealias?

Observations:

  • Implementations are performing the instantiation even when the specialization is merely named for the purposes of producing a reflection (which, in theory, only requires the identity and not the instantiation of the specialization). This extends to the case where substitute is used to form the specialization.
  • Implementations are treating the formation of the pointer-to-reference as being in the immediate context, which does not match the class/function template instantiation model.

Suggested resolution:

Gather input from P2996 paper authors.

Activity

  1. katzdm commented on Oct 20, 2025

    @katzdm

    I agree that it ought to be possible to form a reflection of an alias template specialization (whether through substitute or otherwise) without instantiating the underlying entity. The implemented behavior in the clang prototype is what was expedient at the time, and something that I meant to look into fixing.

    If we like the suggested direction, we should make sure to gather feedback from implementers to check if there are concerns, especially since both experimental implementations separately arrived at the same (possibly undesirable) behavior.

  2. daveedvdv commented on Oct 20, 2025

    @daveedvdv

    IMO, the substitute invocation in the example should throw (and since nothing is caught, the program is ill-formed).

    I consider "alias templates" to be "substituted" (which, as Hubert notes, is an immediate-context process), not "instantiated" (the process that starts a new context).

  3. hubert-reinterpretcast commented on Oct 20, 2025

    @hubert-reinterpretcast
    MemberAuthor

    I consider "alias templates" to be "substituted" (which, as Hubert notes, is an immediate-context process), not "instantiated" (the process that starts a new context).

    That is a lot more clear in a pre-P2996 world where alias templates are quite transparent. With P2996, we are supposed to have an entity (a type alias with a unique identity) associated with the reflection of each specialization of an alias template. The creation of the entity's definition sounds like "instantiation" to me.

  4. hubert-reinterpretcast commented on Oct 20, 2025

    @hubert-reinterpretcast
    MemberAuthor

    It seems the EDG implementation on Compiler Explorer does not maintain the identity of the alias template specialization (https://godbolt.org/z/efbo8T18o):

    #include <experimental/meta>
    
    using namespace std::meta;
    
    template <typename T>
    using A = T *;
    
    static_assert(substitute(^^A, {^^int}) != ^^int *);  // EDG rejects
  5. daveedvdv commented on Oct 20, 2025

    @daveedvdv

    I don't think there is a need to leave the immediate context here. It cannot fail once the substitution of the underlying type-id has succeeded. The type alias being created is just a convenient item to be able to query the origin of the type...

  6. daveedvdv commented on Oct 20, 2025

    @daveedvdv

    It seems the EDG implementation on Compiler Explorer does not maintain the identity of the alias template specialization (https://godbolt.org/z/efbo8T18o):

    #include <experimental/meta>

    using namespace std::meta;

    template
    using A = T *;

    static_assert(substitute(^^A, {^^int}) != ^^int *); // EDG rejects

    Right. I haven't updated the EDG implementation in a loooong time. It's quite out of date wrt. the latest P2996 versions.

  7. hubert-reinterpretcast commented on Oct 20, 2025

    @hubert-reinterpretcast
    MemberAuthor

    I don't think there is a need to leave the immediate context here. It cannot fail once the substitution of the underlying type-id has succeeded. The type alias being created is just a convenient item to be able to query the origin of the type...

    If we want this direction, I think the wording change is to update https://wg21.link/temp.alias#2.sentence-2 to say:

    Any other template-id that names a specialization of an alias template is a typedef-name for a type alias; such a template-id is ill-formed if forming the associated type results in substitution failure.

  8. daveedvdv commented on Oct 20, 2025

    @daveedvdv

    That sounds good to me — thank you!

  9. hubert-reinterpretcast commented on Oct 23, 2025

    @hubert-reinterpretcast
    MemberAuthor

    @jensmaurer, as this is new from C++26, I am interested in having this addressed for plenary in Kona.

  10. jensmaurer commented on Oct 23, 2025

    @jensmaurer
    Member
  11. changed the title [-][temp.inst] Instantiation of type aliases from alias templates unspecified[/-] [+]CWG3099 [temp.inst] Instantiation of type aliases from alias templates unspecified[/+] on Oct 23, 2025
  12. t3nsor commented on Oct 24, 2025

    @t3nsor

    There's no such thing as substitution failure in the standard. What we have is deduction failure (https://eel.is/c++draft/temp.deduct.general#8).

  13. hubert-reinterpretcast commented on Oct 24, 2025

    @hubert-reinterpretcast
    MemberAuthor

    There's no such thing as substitution failure in the standard.

    We already use the term "substitution failure" in various places where we describe situations in which substitution is performed.

  14. t3nsor commented on Oct 25, 2025

    @t3nsor

    There's no such thing as substitution failure in the standard.

    We already use the term "substitution failure" in various places where we describe situations in which substitution is performed.

    Okay, you're right. We use it mostly in notes, but I do see a reference from normative text in ([expr.prim.req.general]/5):

    [...] If the substitution of template arguments into a requirement would always result in a substitution failure, the program is ill-formed; no diagnostic required.

    Whoever wrote this obviously thought that "substitution failure" was a defined term. Otherwise, they would have chosen more straightforward wording, "If the substitution [...] would always fail, [...]".

    Perhaps we should consider providing a definition.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions