I have got problem with the following representative sample code:
template<int I> struct X {}; template<int I> struct Y {}; template<int I> struct XX: X<I> {}; template<int I> struct YY: Y<I> {}; template<template<int> class TP> struct traits; template<> struct traits<X> { template<int I> using Tpl=XX<I>; }; template<> struct traits<Y> { template<int I> using Tpl=YY<I>; }; template<template<int> class TP> struct Z {}; template<template<int> class TP> struct W: Z<traits<TP>::Tpl> {}; int main() { Z<traits<X>::Tpl> zx; Z<traits<Y>::Tpl> zy; W<X> wx; W<Y> wy; return 1; }
This code compiles fine with icc-19.0.0 (and seems to compile with msvc-19.24), but fails to compile with gcc-10.1, clang-10.0.0 and icc-18.0.0.
With gcc-10.1, the error message is:
<source>:32:28: error: type/value mismatch at argument 1 in template parameter list for 'template<template<int <anonymous> > class TP> struct Z'
32 | struct W: Z<traits<TP>::Tpl> {};
| ^
<source>:32:28: note: expected a class template, got 'traits<TP>::Tpl'
Context: I have a template class Z
which have a template template parameter. I would like to derive a class from it, W
, which for the end user accept the same template template parameter as Z
(X
or Y
), but dispatch them to internal classes XX
and YY
which modifies the behavior of X
and Y
by deriving from them.
Is this problem a compiler bug? If yes, is there some kind of workaround?
Many thanks!
You need to tell the compiler that Tpl
is a template:
template<template<int> class TP>
struct W: Z<traits<TP>::template Tpl> {};
// ^^
Afaik, nothing changed about that, I could be that some compilers are / have been more lax about it and let you get away without it.
The reason it is needed is similar to why typename
is needed for types: There could be specializations of traits
where Tpl
is not a template, so you need to tell the compiler that it really is one.