Il pacchetto di parametri deve essere alla fine dell’elenco dei parametri … Quando e perché?

Non capisco il motivo per cui un pacchetto di parametri deve essere alla fine dell’elenco dei parametri se quest’ultimo è associato a una class, mentre il vincolo è rilassato se l’elenco dei parametri è parte di una dichiarazione del metodo membro.

In altri termini, questo compila:

class C { template void fn() { } }; 

Il seguente non:

 template class C { }; 

Perché il primo caso è considerato giusto e il secondo no?
Voglio dire, se è una syntax legale, non dovrebbe essere in entrambi i casi?

Per essere chiari, il vero problema è che stavo definendo una class simile alla seguente:

 template class C { }; 

Avere il tipo di allocatore come l’ultimo tipo sarebbe apprezzato, ma posso aggirarlo in qualche modo (comunque, se hai un suggerimento è apprezzato, forse i tuoi sono molto più eleganti dei miei !!).
Detto questo, ho ricevuto l’errore:

il pacchetto di parametri ‘Args’ deve essere alla fine dell’elenco dei parametri del modello

Quindi, ero solo curioso di comprendere appieno perché è accettato in alcuni casi, ma non è in alcuni altri.

Ecco una domanda simile, ma spiega semplicemente come risolvere il problema e questo era abbastanza chiaro per me.

È valido per i modelli di funzione ma solo quando la deduzione degli argomenti può aiutare il compilatore a risolvere i parametri del modello, poiché l’esempio del modello di funzione è praticamente inutile perché

 template void fn() { } int main() { fn(); } 
 test.cpp: In function 'int main()': test.cpp:2:32: error: no matching function for call to 'fn()' int main() { fn(); } ^ test.cpp:1:57: note: candidate: template void fn() template void fn() { } ^ test.cpp:1:57: note: template argument deduction/substitution failed: test.cpp:2:32: note: couldn't deduce template parameter 'S' int main() { fn(); } 

il compilatore non ha modo di determinare quali parametri template appartengono al pacchetto parametri e quali a S Infatti, come @TC fa notare, dovrebbe in realtà essere un errore di syntax perché un modello di funzione definito in questo modo non può mai essere istanziato.

Un modello di funzione più utile sarebbe qualcosa di simile

 template void fn(S s) { } 

come ora il compilatore è in grado di abbinare in modo univoco il parametro della funzione s al modello di tipo S , con l’effetto collaterale che S sarà sempre dedotto – tutti i parametri del template espliciti dopo il primo apparterranno ad Args .

Nessuna di queste funzioni per i modelli di class (primaria), i parametri non vengono dedotti ed è espressamente vietato:

Dalla bozza n4567

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4567.pdf

[temp.param] / 11

[…] Se un parametro-modello di un modello di class primaria o di un modello alias è un pacchetto di parametri template, deve essere l’ultimo parametro-modello . […]

(se fossero dedotte sarebbe ambiguo come nell’esempio del modello di funzione).

Il primo non è giusto. Il compilatore è solo buggato e non è riuscito a diagnosticarlo. [temp.param] / 11 :

Un pacchetto di parametri template di un template funzione non deve essere seguito da un altro parametro template a meno che quel parametro template possa essere dedotto dalla lista tipo-parametro del template funzione o abbia un argomento default (14.8.2).


Se la funzione tipo T(Args...) è significativa per l’utente finale, un modo per risolvere il problema sarebbe utilizzare una specializzazione parziale invece:

 template class C; //undefined template class C { // implementation }; 

A seconda dei requisiti effettivi, potrebbe valere la pena di considerare anche la cancellazione del tipo di allocatore.