The second example is OK according to the rules. Let us quote them:
#3 A template-argument matches a template template-parameter P when P is at least as specialized as the template-argument A ...
#4A template template-parameter P is at least as specialized as a template template-argument A if, given the following rewrite to two function templates, the function template corresponding to P is at least as specialized as the function template corresponding to A according to the partial ordering rules for function templates. Given an invented class template X with the template-head of A (including default arguments and requires-clause, if any):
- Each of the two function templates has the same template parameters and requires-clause (if any), respectively, as P or A.
- Each function template has a single function parameter whose type is a specialization of X with template arguments corresponding to the template parameters from the respective function template where, for each template parameter PP in the template-head of the function template, a corresponding template argument AA is formed. If PP declares a template parameter pack, then AA is the pack expansion PP... ([temp.variadic]); otherwise, AA is the id-expression PP.
So our template-argument is template<auto> class
and our template parameter is template<int&> class
. Let's invent a class template X
:
template <auto> class X {};
and rewrite as two function templates:
// rewritten argument
template<auto V> void func(X<V>);
// rewritten parameter
template<int& V> void func(X<V>);
The second one seems to be at least as specialized as the first: every function call that would be satisfied by the second template would be also satisfied by the first one. (As far as I can tell the second template can never be satisfied because you cannot instantiate X
with an int&
argument; not sure if this is IFNDR; probably not because the program per se does not contain func
templates, they are invented in order to check other templates).
Less obviously, the first example is also OK according to the same rules. Lety's invent class template X
and rewrite again:
template <int&> class X {};
// rewritten argument
template<int& V> void func(X<V>);
// rewritten parameter
template<auto V> void func(X<V>);
Now the two templates satisfy exactly the same calls, so each one is at least specialized as the other one.
int&
is replaced byint
.template <auto>
is not at least as specialized astemplate <int>
. It should be the other way around. – Anticipantauto
andint&
the compilers however also accept it. I think they basically consider anauto
non-type parameter to match any other non-type parameter in either direction. But I don't see why. – Speiss