Search code examples
c++templatestemplate-specializationtemplate-templatestemplate-aliases

Template template parameter and template alias: compiler bug?


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!


Solution

  • 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.