This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 116a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2025-01-03
(From submission #658.)
Subclause 13.3 [temp.names] paragraph 8 specifies:
When the template-name of a simple-template-id names a constrained non-function template or a constrained template template-parameter , and all template-arguments in the simple-template-id are non-dependent (13.8.3.5 [temp.dep.temp]), the associated constraints (13.5.3 [temp.constr.decl]) of the constrained template shall be satisfied (13.5.2 [temp.constr.constr]).
For template template parameters, it is unclear how this provision interacts with instantiation or substitution. In particular, 13.4.4 [temp.arg.template] paragraph 3 allows for the template template parameter to be more constrained than the argument provided; however, once the parameter is replaced by the corresponding argument, the constraints of the parameter seemingly disappear. Consider:
template <typename T> concept C = false; template <typename> struct Q; template <template <C> class TT> struct A { template <typename T> void f(TT<T> *) {} }; template void A<Q>::f(Q<int> *);
Implementations accept this example. For the reverse situation, where 13.4.4 [temp.arg.template] paragraph 3 allows P to be unconstrained, also consider:
template <typename T> concept C = false; template <typename> struct Q; template <template <typename> class TT, typename T> using Alias = TT<T>; template <template <C> class TT> struct A { Alias<TT, int> *p; }; A<Q> a;
Implementations (other than gcc and clang, which seem not to implement the basic feature at all) appear to use the constraints of TT from A despite the simple-template-id emanating from Alias.
Maybe the constraints from template template parameters should be checked where they appear (including within an alias template) --- or are substituted into an alias template --- to form a simple-template-id once the arguments are known. That is, the associated constraints of both
are checked for simple-template-ids appearing in an alias template.
Also consider:
template <typename T>
concept C = true;
template <typename T>
concept CandMore = C<T> && true;
template <typename> struct Q;
template <template <C> class P, typename T>
using Alias = P<T>;
template <template <CandMore> class TT>
struct A {
Alias<TT, int> *p; // #1
};
A<Q> a;
The P for Alias is not at least as specialized as the argument TT given at #1, if we take the TT constraints as written. However, the actual argument for TT may be such that P is at least as specialized as the argument TT. There is implementation divergence.