Consider this example (also available on wandbox):
template <template <auto> class>
void test() { }
template <int>
struct X { };
Trying to instantiate test<X>()
on clang++
4.0 (trunk) results in a compilation error:
error: no matching function for call to 'test'
test<X>();
^~~~~~~
note: candidate template ignored:
invalid explicitly-specified argument for 1st template parameter
void test() { }
My initial assumption/intuition was that test
could be used to match any template
having a non-type parameter.
However, the following code snippet successfully compiles:
template <template <auto> class>
void test() { }
// vvvv
template <auto>
struct X { };
Is this intended? Could not find anything conclusive in P0127R2.
Which parameter is legal for non-type template? Explanation: The following are legal for non-type template parameters:integral or enumeration type, Pointer to object or pointer to function, Reference to object or reference to function, Pointer to member.
A non-type template argument provided within a template argument list is an expression whose value can be determined at compile time. Such arguments must be constant expressions, addresses of functions or objects with external linkage, or addresses of static class members.
A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)
Class Template Argument Deduction (CTAD) is a C++17 Core Language feature that reduces code verbosity. C++17's Standard Library also supports CTAD, so after upgrading your toolset, you can take advantage of this new feature when using STL types like std::pair and std::vector.
It's definitely intended. Template-template parameters can only match templates which take the same kinds of arguments. This:
template <template <auto> class>
void test() { }
can only be instantiated with a class template that can take any kind of non-type parameter. But this:
template <int>
struct X { };
is not such a class template. X
can only be instantiated with an int
. It simply does not match the specification for the template template parameter, hence the error. What if test
wanted to instantiate its class template with a pointer type? Or pointer to function or pointer to member? That would be impossible.
Your second attempt, with template <auto> struct X { };
does match the template-template parameter, hence is well-formed. Note also that the reverse, having test
take a template <int> class
parameter and passing in template <auto> struct X { };
is also well-formed as the argument is more general than the parameter.
The relevant wording is in [temp.arg.template]:
A template-argument matches a template template-parameter
P
when each of the template parameters in the template-parameter-list of the template-argument’s corresponding class template or alias templateA
matches the corresponding template parameter in the template-parameter-list ofP
. Two template parameters match if they are of the same kind (type, non-type, template), for non-type template-parameters, their types are equivalent (14.5.6.1), and for template template-parameters, each of their corresponding template-parameters matches, recursively.
Note: the equivalence wording accepts the auto
- auto
case and rejects the auto
- int
case, but also seems to reject the int
- auto
case (based on my reading). I'm going to try to get some clarification on it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With