Title
Effect of concept template-head on parameter mappings
Status
open
Section
13.5.4 [temp.constr.normal]
Submitter
Hubert Tong

Created on 2024-12-24.00:00:00 last changed 9 months ago

Messages

Date: 2025-09-23.10:37:12

(From submission #659.)

Consider:

  template <auto> constexpr bool B = true;

  template <unsigned X0> concept C = B<X0>;
  template <unsigned short X1> concept C2 = C<X1>;

  template <unsigned X> void f() requires C<X>; // #1
  template <unsigned X> int f() requires C2<X> && true; // #2

  void g() {
    return f<65536>(); // should probably call #1
  }
  void h() {
    f<0>(); // ambiguous?
  }

The rules in 13.5.4 [temp.constr.normal] bullet 1.4 do not specify how the type of the non-type template parameter X1 in the definition of concept C2 affects the parameter mapping. There is implementation divergence: gcc and MSVC reject the call in g and accept the call in h, resolving to #2 in both cases. Clang and EDG accept the call in g (resolving to #1) and reject the call in h as ambiguous.

As a suggested resolution, introduce a shadow constraint that checks the validity of the template argument for the concept's template parameter when normalizing the use of C2 from #2. This would reject the call to #2 from g (choosing #1) and select #2 as more constrained for the call from h.

Possible resolution:

Change in 13.5.4 [temp.constr.normal] bullet 1.4 as follows:

  • ...
  • For a concept-id C<A1 , A2 , . . . , An > termed CI:
    • If C names a dependent concept, the normal form of CI is a concept-dependent constraint whose concept-id is CI and whose parameter mapping is the identity mapping.
    • Otherwise, to form CE, any non-dependent concept template argument Ai is substituted into the constraint-expression of C. If any such substitution results in an invalid concept-id, the program is ill-formed; no diagnostic is required. The normal form of CI is the conjunction of
      • the result of substituting, in the normal form N of CE, appearances of C's template parameters in the parameter mappings of the atomic constraints in N with their respective arguments from C and
      • for each constant template parameter of some type T of C corresponding to an argument Ai from CI, where the type of Ai is different from T, the normal form of b<Ai>, where b is the invented variable template
        template<T> constexpr bool b = true;
        
        [ Note: This checks that conversion from Ai to T is non-narrowing. -- end note ]
      If any such substitution results in an invalid type or expression, the program is ill-formed; no diagnostic is required. ...
  • ...
History
Date User Action Args
2024-12-24 00:00:00admincreate