15

Ho codice:Specializzazione di un parametro modello di maschera variadic sul numero minimo di argomenti: legale o no?

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

L'idea è che template<typename, typename...> class è un sottoinsieme di template<typename...> class, quindi potrebbe essere possibile specializzarsi su di esso. Ma è piuttosto esoterico, quindi forse no. Proviamolo

GCC 4.7 dice:

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

E 'stato compilato!

L'esecuzione:

$ ./a.out 
77 
99 

Funziona!

Clang 3.1 dice:

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

Chi ha ragione?

risposta

7

Clang sbaglia a rifiutare la specializzazione parziale. Per sapere come interpretare il messaggio errato, è necessario capire quali diagnosi clang. Significa diagnosticare una specializzazione parziale i cui argomenti corrispondono esattamente all'elenco di argomenti impliciti del modello di classe primaria (<param1, param2, ... , paramN>).

Tuttavia gli elenchi di argomenti sono in modo diverso, quindi clang non deve diagnosticare. In particolare, questo non ha nulla a che fare se la specializzazione parziale corrisponde a più o meno argomenti. Considerare

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

La specializzazione parziale qui soddisfa tutto e non più che il modello primario sarebbe partita. E gli elenchi di argomenti di entrambi i modelli sono diversi, quindi questa specializzazione parziale è valida, proprio come te.

+0

Grazie. Esempio affascinante Pensandoci, il mio esempio era solo un caso specifico di quello generale di specializzazione di un parametro modello di template variadic per qualsiasi numero più specifico di parametri (per esempio due). Se provo a fare una specializzazione di 'Foo' per' template class' ottengo lo stesso comportamento: GCC accetta, Clang rifiuta. Inserirò un bug (se non è stato fatto). Una citazione dello standard mi renderebbe felice, se non è troppo disturbo. – glaebhoerl

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

c'è più specializzata di

template<template<typename...> class> 

Entrambi di loro prende un elenco di parametri di tipo sconosciuto. è solo che il primo prende un membro di questa lista come parametro diverso. Non contiene informazioni aggiuntive sul tipo in modo che il compilatore debba selezionarne uno sull'altro.

Nell'uso tipico di modelli variadic questa specializzazione viene generata in termini di conteggio dei parametri. Pensando ai modelli variadici come funzioni ricorsive durante il runtime, dovresti semplicemente fornire la condizione di terminazione (come una classe che prende solo un tipo sconosciuto).

Clang è molto appassionato di diagnostica, quindi penso che stia rilevando l'anomalia e che giustamente dia errori. GCC è in grado di compilarlo è strano. Forse perché stai specificando esplicitamente quali modelli utilizzare in struct A e struct B separatamente, gcc è riuscito a capirlo e sopprimere l'anomalia.

+1

C'è una differenza. Uno di questi corrisponde a "modelli di classe con zero o più parametri typename", l'altro corrisponde a "modelli di classe con uno o più parametri typename". Infatti, se provate a passare 'template struct A {}' come argomento template dove il parametro è di tipo 'template class', sia Clang che GCC lo rifiuteranno.Naturalmente questo non significa che lo standard linguistico consenta anche la specializzazione basata su questa distinzione. Se fornisci una citazione, sarò felice di accettare. – glaebhoerl

+0

In un altro modo, se è possibile specializzarsi in base al numero di argomenti quando sono in una posizione positiva - 'modello ' versus 'template ' - Non vedo alcun ostacolo teorico a consentendole anche quando si trovano in una posizione negativa, 'template