2

I am considering Class1, Class2, Class3.

Class2 and Class3 have a partial specialisation with int, so they are identical in their definition.

On the other hand, Class1 has a specialisation for Class3<T> and for a general template template with only one argument, i.e. Unary<T>. So Class1 has no specialisation for Class2<T>.

It happens that Class1 <Class3<T>>::type is actually Class3<T>. Indeed I explicitly wrote the specialisation. However, the compiler says Class1 <Class2<T>>::type it is not defined. But I defined the specialisation for a the template template case, Class1<Unary<T>>. Why is the compiler not recognising it? How can I make the compiler choose the most specialised case (Class1 <Class3<T>>::type), if it exists, and, if does not, the template template case (Class1<Unary<T>>)? Thank you

template<typename...T>
class Class1;

template<typename...T>
class Class2;

template<typename...T>
class Class3;

template<>
class Class2<int>
{};

template<>
class Class3<int>
{};

template<typename T>
class Class1<Class3<T>>
{
 public:
  using type=Class3<T>;
};

template<template<class> class Unary, typename T>
class Class1<Unary<T>>
{
 public:
  using type=Unary<T>;
};
Garo
  • 111
  • 7
  • Interesting: Compare gcc and clang in the case of [matching an actual unary template](https://godbolt.org/z/13dooB), vs [matching a variadic template](https://godbolt.org/z/68kIWV) against the unary template template argument. Both compilers do the former, but clang rejects the latter (while gcc accepts it). I assume you are using clang? (Both are also happy given a variadic template for deducing a variadic template template argument: https://godbolt.org/z/Fhrb4B) – Max Langhof Oct 17 '19 at 11:57
  • I don't understand your question. You know that "Class1 has no specialisation for Class2" because the unary specialization is related to a "template template with only one argument" but you're surprised that "However, the compiler says Class1 >::type it is not defined. But I defined the specialisation for a the template template case, Class1>". – max66 Oct 17 '19 at 12:00
  • @MaxLanghof - observe that both compilers fail with the later (also gcc) compiling with C++14 instead of C++17. The language is changed in C++17 so I suspect that g++ is conformant and clang++ isn't. – max66 Oct 17 '19 at 12:07
  • @max66 It boils down to "can you pass a variadic template as an unary template template argument?". Based on the 3 main compiler votes, it seems that the answer is "in C++14 you can't, in C++17 you can". But that's the question. – Max Langhof Oct 17 '19 at 12:24
  • @MaxLanghof yup, C++17 reduced the constraints on matching variadic template template arguments and template template arguments with defaulted values – bartop Oct 17 '19 at 12:26
  • 1
    Related question: https://stackoverflow.com/questions/48645226/template-template-parameter-and-default-values – bartop Oct 17 '19 at 12:27

1 Answers1

1

Before C++17 such template:

template<template<class> class Unary, typename T>
class Class1<Unary<T>>

should not mach with variadic templates. Same for templates with defaulted arguments (check this with std::vector for example) - Template template parameter and default values. It was a defect in standard and fix came in C++17

bartop
  • 9,971
  • 1
  • 23
  • 54