Consider the following code:
template<typename>
struct One {};
template<typename, typename>
struct Two {};
template<template<typename...> class TTP, typename...>
struct SS;
#ifdef TEST_TTP
template<template<typename> class OneParam,
typename... Ts>
struct SS<OneParam, Ts...> {};
template<template<typename, typename> class TwoParam,
typename... Ts>
struct SS<TwoParam, Ts...> {};
#else // TEST_TTP
template<template<typename> class OneParam,
typename TParam>
struct SS<OneParam, TParam> {};
template<template<typename, typename> class TwoParam,
typename TParam1,
typename TParam2>
struct SS<TwoParam, TParam1, TParam2> {};
#endif // TEST_TTP
int main() {
SS<One, int> ssoi;
SS<Two, int, int> sstii;
}
This code will compile properly on Clang, GCC, and MSVC, if TEST_TTP
isn't defined. However, if it is defined...
- The code compiles properly on GCC, indicating that it recognises that
OneParam
andTwoParam
are distinct fromTTP
in the primary template. - Clang fails to recognise that
OneParam
specialisesTTP
, causing it to emit two errors (the first being that the partial specialisation doesn't specialise any template parameters, and the second being thatOneParam
conflicts with the previously-declared template template parameter). It then emits similar errors forTwoParam
(the first is identical, while the second says that the template template parameter has too many parameters), and an error for each instantiation ofSS
(because it considers the template to be undefined), for a total of 6 errors. - MSVC emits similar errors to Clang, but more concisely: It emits C3855 (
OneParam
is incompatible with the primary template), and a C2079 (variable uses undefined type) for each instantiation ofSS
, for a total of 3 errors.
Demonstrated live on Coliru.
From my testing:
GCC allows a template with a template template parameter which takes a variadic parameter pack to be partially specialised based solely on the number of parameters that template template parameter takes. Clang and MSVC do not.
template<template<typename...> class T> struct S;
template<template<typename> class T> struct S<T> {}; // Only works with GCC.
template<template<typename, typename> class T> struct S<T> {}; // Only works with GCC.
Clang and MSVC are fine with this if other parameters are also specialised, however.
template<template<typename...> class T, typename... Ts> struct S;
template<template<typename> class T,
typename TParam>
struct S<T, TParam> {};
template<template<typename, typename> class T,
typename TParam1,
typename TParam2>
struct S<T, TParam1, TParam2> {};
It would thus appear that either the former isn't legal C++, or it isn't properly supported by Clang and MSVC. So, the question is this:
Considering this, what is the proper, legal syntax for partially specialising a template, which contains a template template parameter, based on the number of parameters that template template parameter takes? If there is no legal syntax for this, is supporting it a GCC extension and/or bug?
If a full record of the tests I performed, along with the original example which prompted this question, are desired, please see the edit history.