专门针对最小参数数量的可变参数模板模板参数:合法与否?

时间:2012-03-19 14:45:37

标签: c++ templates c++11 template-specialization variadic-templates

我有代码:

#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);
}

我的想法是template<typename, typename...> classtemplate<typename...> class的一个子集,因此可能会专注于它。但它非常深奥,所以也许不是。我们来试试吧。

GCC 4.7说:

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

编译了!

运行它:

$ ./a.out 
77
99

有效!

Clang 3.1说:

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

谁是对的?

2 个答案:

答案 0 :(得分:8)

Clang拒绝部分专业化是错误的。要知道如何解释错误消息,您需要了解clang诊断的内容。它意味着诊断部分特化,其参数完全匹配主类模板(<param1, param2, ... , paramN>)的隐式参数列表。

然而,参数列表不同,所以clang不会诊断它。特别是这与部分特化与或多或少的参数匹配无关。考虑

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

此处的部分特化匹配所有内容,而不是主模板匹配的内容。两个模板的参数列表都不同,所以这个部分特化是有效的,就像你的一样。

答案 1 :(得分:4)

`template<template<typename, typename...> class C> 

并不比

更专业
template<template<typename...> class>

它们都采用未知类型参数列表。只是前者将此列表中的一个成员作为不同的参数。 它不包含有关类型的其他信息,以便编译器应选择一个而不是另一个。

在可变参数模板的典型用法中,这种特化是根据参数计数生成的。在运行时期间将可变参数模板视为递归函数,您应该只提供终止条件(作为只接受一种未知类型的类)。

Clang非常热衷于诊断,因此我认为它正在捕捉异常并正确地给出错误。 GCC能够编译它很奇怪。也许是因为您明确指定了struct Astruct B中单独使用的模板,gcc能够捕获并抑制异常。