2012-11-22 6 views
21

Während ich einige C++ 11-Code mit beiden GCC 4.7.2 und Clang 3.1 kompiliert, stieß ich auf ein Problem mit Clang nicht zu einem Argument Argument wo abzuleiten GCC ist erfolgreich. In einer abstrakteren Form sieht der Code wie folgt aus:Variadic Vorlage als Vorlage Parameter: Abzug arbeitet mit GCC, aber nicht mit 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; 
} 

die Beispiele in §14.3.3 und die Spezifikationen in §14.8.2 der Standard Aus der Lektüre Ich denke, der Abzug sollte funktionieren, aber ich kann es nicht sicher sagen. Dies ist der Ausgang, den ich vom Gebäude bekomme:

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 

Warum unterscheiden sich die Ergebnisse? Ist GCC schlampig, Clang dumm, enthält mein Code nicht spezifiziertes Verhalten oder alle?

+0

Ich stimme dir zu. Alles, was ich im endgültigen C++ 11-Entwurf gesehen habe, würde zeigen, dass dies funktionieren sollte. 14.3.3.3 ist besonders relevant. –

+0

Ihr Beispiel fehlt ein 'typedef int Element;', oder? – Quuxplusone

+0

Nein, am Anfang des Codes definiere ich eine Struktur mit dem Namen Element. – psyill

Antwort

7

Clang versucht, die Argumente für diesen Aufruf zu folgern:

processVariadic(SecondContainer<Element>{}); 

Da SecondContainer eine Standard-Template-Argument hat, dies entspricht:

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

So führt er Abzug Template-Argument mit P = Container<Element> und A = SecondContainer<Element, Element>. Es kann sofort abgeleitet werden, dass der Vorlagenparameter ContainerSecondContainer ist.

Als nächstes betrachtet es die Vorlage Argumente. Da der Argumenttyp vollständig aufgelöst ist, glaubt Clang, dass der Parameter so viele Typen haben muss oder dass der Abzug möglicherweise nicht erfolgreich sein kann (er berücksichtigt keine Standardargumente). Es kennzeichnet also einen Deduktionsfehler.


Also, was soll passieren? In den Worten von [temp.deduct.type]p8,

Ein Vorlagentyp Argument T, ein Template-Template-Argument TT oder eine Vorlage nicht-Typ Argument i abgeleitet werden kann, wenn P und A haben eine der folgenden Formen annehmen:
[...]
TT<T>
TT<i>
TT<>
wo [...] <T> Listen Template-Argument darstellt, in dem mindestens ein arg enthält eine T, <i> repräsentiert Vorlage Argumentlisten, wobei mindestens ein Argument enthält eine i und <> stellt Vorlage Argumentlisten, wo kein Argument enthält eine T oder i.

Um die Vorlage Argumente übereinstimmen, wenden wir uns an [temp.deduct.type]p9:

Wenn P eine Form hat, die <T> oder <i> enthält, dann jedes Argument Pi der jeweiligen Template-Argument Liste P verglichen mit das entsprechende Argument Ai der entsprechenden Vorlage Argumentliste von A.

Hier sind zwei Dinge zu beachten. Eine besagt, dass diese Regel nicht sagt, was passiert, wenn die Listen Pi und Ai unterschiedliche Längen haben (wie sie in diesem Fall sind), und die übliche Interpretation scheint zu sein, dass die nicht übereinstimmenden Elemente nicht untersucht werden. Zum anderen sollte diese Regel nicht beachtet werden, da das Formular P keine <T> oder <i> enthält (es enthält nur <>, da keine Template-Parameter darin enthalten sind).


Also, Clang war falsch, diesen Code abzulehnen. Ich habe es in r169475 behoben.