Специализация параметра шаблона вариационного шаблона на минимальном количестве аргументов: законно или нет? - PullRequest
16 голосов
/ 19 марта 2012

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

#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...> class - это подмножество template<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 ]

8 голосов
/ 20 марта 2012

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

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

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

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

4 голосов
/ 20 марта 2012
`template<template<typename, typename...> class C> 

не более специализирован, чем

template<template<typename...> class>

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

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

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

...