AlwaysLearning AlwaysLearning - 2 months ago 11
C++ Question

Using a specialization of variadic template as a template argument

Consider the following:

template <class...>
struct MyT;

template <class T>
struct MyT<T> {};

template <template <class> class TT = MyT> struct A {}; // fine

using B = A<MyT>; // does not compile

int main() {
return 0;
}


When
MyT
is used as a default argument of
A
, the compiler (g++ 5.4.0) is happy. However, when it is used to instantiate
A
, the story is different:

temp.cpp:19:16: error: type/value mismatch at argument 1 in template parameter list for ‘template<template<class> class TT> struct A’
using B = A<MyT>;
^
temp.cpp:19:16: note: expected a template of type ‘template<class> class TT’, got ‘template<class ...> struct MyT’


I can fix it by introducing an alias:

template <class T>
using MyTT = MyT<T>;

using B = A<MyTT>; // fine


The question: what is the reason for the error and is there a solution without introducing an alias?

EDIT Please note that
A
is declared to have a template template parameter as shown and that is not given for change.

Answer

You cannot do that and you cannot use such a type as a default parameter. The fact that it seems to be accepted as long as you don't rely on it doesn't mean that the default parameter is a valid one.
Consider the following code that explicitly uses the default type:

template <class...>
struct MyT;

template <class T>
struct MyT<T> {};

template <template <class> class TT = MyT> struct A {}; // fine

int main() {
  A<> a;
  return 0;
}

The error is quite clear:

template template argument has different template parameters than its corresponding template template parameter

Partial specializations are not taken in account in this case, thus the two declarations differ.
You should either declare A as:

template <template <class...> class TT = MyT> struct A;

Or declare somewhere a type that is constrained to a single argument, as an example by means of an using declaration as you did.