2012-11-22 15 views
21

Durante la compilazione di codice C++ 11 con GCC 4.7.2 e Clang 3.1, ho riscontrato un problema con Clang che non riusciva a dedurre un argomento modello in cui GCC ha successo. In una forma più astratta, il codice simile a questo:Modello Variadic come parametro template: la deduzione funziona con GCC ma non con Clang

src/test.cc:

struct Element { 
}; 

template <typename T> 
struct FirstContainer { 
}; 

template <typename T, typename U = Element> 
struct SecondContainer { 
}; 

template <template <typename> class Container> 
void processOrdinary(Container<Element> /*elements*/) { 
} 

template <template <typename, typename> class Container> 
void processOrdinary(Container<Element, Element> /*elements*/) { 
} 

template <template <typename, typename...> class Container> 
void processVariadic(Container<Element> /*elements*/) { 
} 

int main() { 
    // This function instantiation works in both GCC and Clang. 
    processOrdinary(FirstContainer<Element>{}); 
    // This function instantiation works in both GCC and Clang. 
    processOrdinary(SecondContainer<Element>{}); 
    // This function instantiation works in both GCC and Clang. 
    processVariadic(FirstContainer<Element>{}); 
    // This function instantiation works in both GCC and Clang. 
    processVariadic<SecondContainer>(SecondContainer<Element>{}); 
    // This function instantiation works in GCC but not in Clang. 
    processVariadic(SecondContainer<Element>{}); 
    return 0; 
} 

Dalla lettura degli esempi in §14.3.3 e le specifiche in §14.8.2 dello standard Penso che la deduzione dovrebbe funzionare, ma non posso dirlo con certezza. Questo è l'output che ottengo dall'edificio:

mkdir -p build-gcc/ 
g++ -std=c++0x -W -Wall -Wextra -Weffc++ -pedantic -c -o build-gcc/test.o src/test.cc 
g++ -o build-gcc/test build-gcc/test.o 
mkdir -p build-clang/ 
clang++ -std=c++11 -Weverything -Wno-c++98-compat -c -o build-clang/test.o src/test.cc 
src/test.cc:34:3: error: no matching function for call to 'processVariadic' 
    processVariadic(SecondContainer<Element>{}); 
    ^~~~~~~~~~~~~~~ 
src/test.cc:21:6: note: candidate template ignored: failed template argument deduction 
void processVariadic(Container<Element> /*elements*/) { 
    ^
1 error generated. 
make: *** [build-clang/test.o] Fel 1 

Perché i risultati differiscono? È GCC sciatto, Clang stupido, il mio codice contiene un comportamento non specificato o tutti?

+0

Sono d'accordo con te. Tutto ciò che ho visto nella bozza finale del C++ 11 dovrebbe indicare che questo dovrebbe funzionare. 14.3.3.3 è particolarmente rilevante. –

+0

Nell'esempio manca un 'typedef int Element;', giusto? – Quuxplusone

+0

No, all'inizio del codice definisco una struttura con il nome Elemento. – psyill

risposta

7

Clang sta cercando di dedurre gli argomenti per il presente invito:

processVariadic(SecondContainer<Element>{}); 

Dal SecondContainer ha un argomento di template di default, questo equivale a:

processVariadic(SecondContainer<Element, Element>{}); 

Così, si effettua la deduzione modello di discussione con P = Container<Element> e A = SecondContainer<Element, Element>. Si può immediatamente dedurre che il parametro di modello Container è SecondContainer.

Successivamente, considera gli argomenti del modello. Poiché il tipo di argomento è completamente risolto, Clang ritiene che il parametro debba avere un numero di tipi diverso, altrimenti la deduzione non può avere esito positivo (non prende in considerazione gli argomenti predefiniti). Quindi contrassegna un errore di deduzione.


Quindi, cosa dovrebbe succedere? Nelle parole di [temp.deduct.type]p8,

Un tipo di modello argomento T, un argomento template TT o un argomento di template non di tipo I si può dedurre se P e A avere una delle seguenti forme:
[...]
TT<T>
TT<i>
TT<>
in cui [...] <T> rappresenta liste di argomenti di template in cui almeno un arg ument contiene un T, <i> rappresenta elenchi di argomenti di template in cui almeno un argomento contiene un i e <> rappresenta liste di argomenti di template in cui nessun argomento contiene un T o un i.

Al fine di corrispondere gli argomenti di modello, ci rivolgiamo a [temp.deduct.type]p9:

Se P ha una forma che contiene <T> o <i>, quindi ogni argomento Pi del rispettivo modello di lista degli argomenti P viene confrontato con l'argomento corrispondente Ai dell'elenco di argomenti modello corrispondente di A.

Ci sono due cose da osservare qui. Uno è che questa regola non dice cosa succede se la lista Pi e Ai sono lunghezze diverse (come in questo caso), e l'interpretazione comune sembra essere che gli articoli non corrispondenti non vengono esaminati. L'altro è che questa regola non deve essere seguita comunque, poiché il formato P non contiene <T> o <i> (contiene solo <>, perché non ci sono parametri del modello in esso).


Quindi, Clang ha sbagliato a rifiutare questo codice. L'ho risolto in r169475.

Problemi correlati