Specializing a variadic template template paramete

2019-04-03 19:07发布

I have code:

#include <cstdio>

template<template<typename...> class>
struct Foo 
{ 
    enum { n = 77 };
};

template<template<typename, typename...> class C>
struct Foo<C>
{
    enum { n = 99 }; 
};

template<typename...> struct A { };

template<typename, typename...> struct B { };

int main(int, char**)
{
    printf("%d\n", Foo<A>::n);
    printf("%d\n", Foo<B>::n);
}

The idea is that template<typename, typename...> class is a subset of template<typename...> class, so it might be possible to specialize on it. But it's pretty esoteric, so maybe not. Let's try it out.

GCC 4.7 says:

$ g++ -std=c++11 test157.cpp 

It compiled!

Running it:

$ ./a.out 
77
99

It works!

Clang 3.1 says:

$ clang++ -std=c++11 test157.cpp
test157.cpp:10:8: error: class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list
struct Foo<C>
       ^  ~~~
test157.cpp:9:10: error: too many template parameters in template template parameter redeclaration
template<template<typename, typename...> class C>
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test157.cpp:3:10: note: previous template template parameter is here
template<template<typename...> class>
         ^~~~~~~~~~~~~~~~~~~~~
2 errors generated.

Who's right?

2条回答
三岁会撩人
2楼-- · 2019-04-03 19:57

Clang is wrong to reject the partial specialization. To know how to interpret the errormessage, you need to understand what clang diagnoses. It means to diagnose a partial specialization whose arguments match exactly the implicit argument list of the primary class template (<param1, param2, ... , paramN>).

However the argument lists are differently so clang shall not diagnose it. In particular this has nothing to do wheter the partial specialization matches more or less arguments. Consider

template<typename A, typename B> class C;
template<typename B, typename A> class C<A, B> {};

The partial specialization here matches everything and not more that the primary template would match. And the argument lists of both templates are different so this partial specialization is valid, just like you'rs.

查看更多
一纸荒年 Trace。
3楼-- · 2019-04-03 20:04
`template<template<typename, typename...> class C> 

is no more specialized than

template<template<typename...> class>

Both of them takes a list of unknown type parameters. it is just that the former takes one member of this list as a different parameter. It contains no additional info about the type such that the compiler should select one over the other.

In the typical usage of variadic templates this specialization is generated in terms of parameter count. Thinking about the variadic templates as recursive functions during runtime, you should just supply the terminating condition (as a class taking only one unknown type).

Clang is very keen on diagnostics so I think it is catching the abnormality and rightfully giving errors. GCC's being able to compile it is strange. Maybe because you are explicitly specifying which templates to use in struct A and struct B seperately, gcc was able to catch that and suppress the abnormality.

查看更多
登录 后发表回答