Ho recentemente creato questo codice di esempio per illustrare l'utilizzo della funzione del modello variadico C++ 11.Necessità delle funzioni del modello di dichiarazione anticipata
template <typename Head, typename... Tail> void foo (Head, Tail...);
template <typename... Tail> void foo (int, Tail...);
void foo() {}
template <typename... Tail>
void foo (int x, Tail... tail)
{
std :: cout << "int:" << x;
foo (tail...);
}
template <typename Head, typename... Tail>
void foo (Head x, Tail... tail)
{
std :: cout << " ?:" << x;
foo (tail...);
}
foo (int (123), float (123)); // Prints "int:123 ?:123.0"
Se le prime due linee che forward-dichiarano foo
sono omessi allora questo stamperà int:123int:123
invece. Questo ha sorpreso un programmatore C++ esperto e competente.
Era convinto che le dichiarazioni anticipate non dovessero essere necessarie perché il corpo non verrà istanziato fino alla seconda fase di ricerca a due fasi. Pensa che il compilatore (gcc 4.6) ha un bug.
Credo che il compilatore è proprio perché i due foo
sono different base template functions e la scelta del modello di base deve essere locked-in durante la prima fase altrimenti si potrebbe violare la regola una definizione istanziando foo
prima di tutte le versioni di esso sono stati definiti e quindi di nuovo in seguito (considerare come il linker presuppone che le definizioni di funzioni del template ridondanti siano identiche, intercambiabili e scartate).
Quindi, chi ha ragione?
Il GotW sopra-linked ben spiega come e perché i modelli di funzione non parzialmente specializzati, ma l'esistenza di funzioni template variadic sembra aumentare la confusione - l'intuizione che foo<int,Tail...>
dovrebbe essere una specializzazione parziale di foo<Head,Tail...>
è più forte di quell'intuizione per le funzioni non-variadiche, almeno per me.
FWIW, clang ++ produce lo stesso risultato di gcc. – Cubbi
Non sono esattamente sicuro, ma sembra che quando viene chiamato il foo(), dovrebbe istanziare il foo (int, Tail ...) che poi prova foo (tail ...) e quando la forward forward non è lì , non vedrà il foo (Head, Tail ...) e può solo scegliere il foo (int, Tail ...) uno ... Puoi anche aggiungere una chiamata a bar (x); nel foo (int, Tail ...) e quindi dichiarare una barra() dopo tutte le funzioni foo() ... non verrà trovato anche – PlasmaHH