Специализируясь на параметре шаблона variadic template на минимальном количестве аргументов: legal или нет?

у меня есть код:

#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("%dn", Foo<A>::n);
    printf("%dn", Foo<B>::n);
}

идея в том, что template<typename, typename...> class - это подмножество template<typename...> class, поэтому можно было бы специализироваться на этом. Но это довольно эзотерично, так что, возможно, нет. Давай попробуем.

на GCC 4.7 говорит:

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

оно компилируется!

работает это:

$ ./a.out 
77
99

это работает!

лязгом 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 ответов


Clang неправильно отвергать частичную специализацию. Чтобы знать, как интерпретировать ошибку, нужно понимать, что такое clang diagnoses. Это означает диагностировать частичную специализацию, аргументы которой точно соответствуют неявному списку аргументов шаблона первичного класса (<param1, param2, ... , paramN>).

однако списки аргументов по-разному, поэтому clang не должен диагностировать его. В частности, это не имеет никакого отношения к тому, что частичная специализация соответствует более или менее аргументам. Считать

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

частичная специализация здесь соответствует всему и не более, чем основной шаблон будет соответствовать. И списки аргументов обоих шаблонов различны, поэтому эта частичная специализация действительна, как и you'R.


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

не более

template<template<typename...> class>

оба они принимают список неизвестных параметров типа. просто первый принимает один член этого списка в качестве другого параметра. Он не содержит дополнительной информации о типе, так что компилятор должен выбрать один над другим.

в типичное использование шаблонов с переменным количеством аргументов этой специализации формируется с точки зрения числа параметров. Думая о шаблоны с переменным числом аргументов, как рекурсивный функции во время выполнения вы должны просто указать условие завершения (как класс, принимающий только один неизвестный тип).

Clang очень увлечен диагностикой, поэтому я думаю, что он ловит аномалию и по праву дает ошибки. ССЗ уметь компилировать странно. Возможно, потому, что вы явно указываете, какие шаблоны использовать в struct A и struct B отдельно, gcc смог поймать это и подавить аномалию.