16

prima un po 'di codice, poi alcuni contesto, allora la domanda:variadic alias template come argomenti di template

template <typename T> using id = T; 

template <template <typename...> class F, typename... T> 
using apply1 = F <T...>; 

template <template <typename...> class F> 
struct apply2 
{ 
    template <typename... T> 
    using map = F <T...>; 
}; 

// ... 

cout << apply1 <id, int>() << endl; 
cout << apply2 <id>::map <int>() << endl; 

Sia clang 3.3 e gcc 4.8.1 compilare questo senza errori, applicando il metafunction identità int, così sia le espressioni restituiscono un valore predefinito int (zero).

Il fatto che id è un po 'template <typename>apply1, apply2 si aspettano un template <typename...> fatto mi riguardano, in primo luogo. Tuttavia, è abbastanza comodo che questo esempio funziona perché altrimenti METAFUNCTIONS come apply1, apply2 dovrebbero essere molto più coinvolti.

D'altro canto, tali alias del modello causano seri problemi nel codice reale che non riesco a riprodurre qui: errori interni del compilatore frequenti per gcc e comportamento inaspettato meno frequente per clang (solo nei test SFINAE più avanzati).

Dopo mesi di tentativi ed errori, io ora installare e provare il codice a (sperimentale) gcc 4.9.0, ed ecco che arriva l'errore:

test.cpp: In instantiation of ‘struct apply2<id>’: 
test.cpp:17:22: error: pack expansion argument for non-pack parameter ‘T’ of alias template ‘template<class T> using id = T’ 
    using map = F <T...>; 
        ^

Ok, quindi sembra che questo codice non è stato valido tutto questo tempo, ma gcc si è bloccato in vari modi invece di segnalare l'errore. È interessante notare che, mentre apply1, apply2 sembrano essere equivalenti, l'errore viene registrato soltanto per apply2 (che è molto più utile nella pratica). Per quanto riguarda il clang, davvero non posso dire.

In pratica, a quanto pare non ho altro modo se non di andare avanti con gcc 4.9.0 e correggere il codice, anche se diventerà molto più complesso.

In teoria, vorrei sapere che cosa dice la norma: è questo codice valido? In caso contrario, è valido anche l'uso di apply1? o solo apply2?

EDIT

Giusto per chiarire che tutti i problemi che ho avuto finora si riferiscono ad alias di template, non struct modello. Ad esempio, si consideri la seguente modifica:

template <typename T> struct id1 { using type = T; }; 

// ... 

cout << typename apply1 <id1, int>::type() << endl; 
cout << typename apply2 <id1>::map <int>::type() << endl; 

Questo compila bene e stampe 0 in entrambi i casi, il clangore 3.3, gcc 4.8.1, gcc 4.9.0.

Nella maggior parte dei casi, le mie soluzioni hanno introdotto un modello di struct intermedio prima l'alias. Tuttavia, ora sto cercando di utilizzare METAFUNCTIONS per parametrizzare test SFINAE generici e in questo caso devo usare gli alias direttamente, perché le strutture non devono essere istanziati. Solo per avere un'idea, un pezzo del codice attuale è here.

+3

Il messaggio di errore del GCC 4.9 sperimentale non ha senso per me, e FWIW penso che il codice sia valido. –

+0

correlati? http://stackoverflow.com/q/18724698/420683 – dyp

+0

Grazie, questa domanda è correlata in quanto i modelli che trattano casi speciali come 'foo',' foo2', 'foo_variadic' ecc. sono esattamente come pensavo di correggere il codice se devo. Tuttavia, come ho modificato sopra, i miei problemi compaiono solo con gli alias del modello. – iavr

risposta

3

ISO C++ 11 14.3.3/1:

A template-argument for a template template-parameter shall be the name of a class template or an alias template, expressed as id-expression.

Inoltre non vedo alcuna eccezione speciali per i parametri di modello template variadic.

On the other hand, such template aliases cause serious problems in real-world code that I cannot reproduce here: frequent internal compiler errors for gcc, and less frequent unexpected behavior for clang (only in more advanced SFINAE tests).

La radice di problemi può essere in altri luoghi.Dovresti provare a localizzare il codice che causa l'errore interno del compilatore - rimuovi le parti non correlate una ad una (o usa una qualche specie di ricerca binaria, cioè divide e conquista) - e controlla se l'errore è ancora qui su ogni fase.


Nel caso di GCC 4.9.0 errore, provare a cambiare

template <typename... T> 
using map = F <T...>; 

a

template <typename... U> 
using map = F <U...>; 

Forse questo potrebbe aiutare a capire che cosa GCC vede.

+0

Grazie. Non sono stato in grado di isolare il codice che è in errore in passato, perché la rimozione di anche piccole parti ha fatto scomparire gli errori. Con gcc 4.9 questa era la prima volta che vedevo un chiaro messaggio di errore, ed ero "felice" perché se fosse vero, poteva spiegare quasi tutto (anche se ogni soluzione sarebbe brutta). Comunque, dato che i problemi sono ancora lì, proverò a fare un nuovo esempio con risultati inaspettati in altri compilatori e tornerò con una nuova domanda. – iavr

Problemi correlati