简体   繁体   中英

Can C++17's deduced `auto` non-type `template` parameters pattern-match templates with explicit non-type parameters?

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 .

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 template A matches the corresponding template parameter in the template-parameter-list of P . 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.

In addition to Barry's answer, which made me curious, here are the four possible combinations and results using Clang 4.0 (SVN), see also on wandbox :

template <bool> struct obj_bool { };  // object taking a value of boolean type
template <auto> struct obj_auto { };  // object taking a value of deduced type
//       ^^^^^^ Note: this is a template value argument (non-type template argument)

template <template <auto> typename> void fn_auto() { }
template <template <bool> typename> void fn_bool() { }
//        ^^^^^^^^^^^^^^^^^^^^^^^^ Note: this is a template type argument
//                 ^^^^^^                taking a template value argument

int main() {     
    fn_bool<obj_bool>();    // #1 bool->bool OK (exact match)
    fn_auto<obj_auto>();    // #2 auto->auto OK (exact match)
    fn_bool<obj_auto>();    // #3 bool->auto OK (sub-set)
    //fn_auto<obj_bool>();  // #4 auto->bool Error: no matching function.
}

From that, #1 and #2 are obviously exact matches and are working as expected. #3 would invoke the bool implementation on a template that can handle not only bool but all types, whereas #4 would try to invoke a definition expecting a generalized object (auto) with an object providing only a sub-set (bool) of possibilities.

The templated function fn_auto promises possible instantiations for templates taking any value type (auto). Thus giving it only a sub-set of possibilities (bool) violates this promise.

Though not immediately obvious, the restriction makes sense. And sorry for my wording not being C++ Standard compliant.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM