2016-06-05 7 views
3

den Code vor:Klirren nicht schließen nicht Template-Argument in variadische Template-Funktion mit varargs

#include <tuple> 

template<class... Args, class T> 
T method(std::tuple<Args...>, Args..., T, ...) { 
    return T(); 
} 

int main() { 
    method(std::make_tuple<int, float, double>(1, 1.0f, 1.0), 
     1, 1.0f, 1.0, 1); 
} 

g++ seit 4.9 hat kein Problem damit zu kompilieren. clang++ auf der anderen Seite liefert einen Fehler:

main.cpp:9:5: error: no matching function for call to 'method' 
    method(std::make_tuple<int, float, double>(1, 1.0f, 1.0), 
    ^~~~~~ 
main.cpp:4:3: note: candidate template ignored: couldn't infer template argument 'T' 
T method(std::tuple<Args...>, Args..., T, ...) { 
^
1 error generated. 

Welche Compiler ist richtig?

+0

So funktioniert es: 'Args ...' auf der Toplevel ist nicht am Ende der Parameterliste, so dass es in einem nicht abgeleiteten Kontext erscheint, der 'Args ... macht. 'ist äquivalent zu einer 0-dimensionalen Parameter-Unterliste während der Mustervergleichs-Argumentableitung. Das nachfolgende "T" passt also auf "1", das nach dem Tupel-Argument erscheint, und wird zu "int" abgeleitet. Später, wenn der Compiler in "Args" ...'Die Argumente' int, float, double', die Parameterliste compile ist 'tuple <...>, int, float, double, int'. Diese Liste muss den Argumenttypen entsprechen. –

+0

es geschieht in diesem Fall zufällig, da der letzte '1's Typ der gleiche ist wie der erste' 1's Typ (GCC scheint eigentlich nicht zu interessieren. Es kompiliert auch, wenn die letzte '1'' 1.0' ist. Interessanterweise bleibt 'T'' int'). Vielleicht gibt clang auf, wenn die Packexpansion der drei Typen in 'Args ...' das 'T', das als 'int' abgeleitet wurde, von seiner früheren Ableitungsargumentposition verschiebt und berichtet, dass es'T' nicht ableiten konnte . –

+0

Leider enthält http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1388 kein Beispiel für Ihren Fall. Vielleicht ist es eine Nachricht wert, um eine Diskussion zu führen. –

Antwort

1

Der Code ist schlecht formatiert. Beide Compiler nicht korrekt kompilieren:

#include <tuple> 

template<class... Args, class T> 
T method(std::tuple<Args...>, Args..., T) { 
    return T(); 
} 

int main() { 
    method(std::make_tuple<int, float, double>(1, 1.0f, 1.0), 
     1, 1.0f, 1.0, 1); 
} 

Wir haben von [temp.deduct.call], Hervorhebung von mir:

When a function parameter pack appears in a non-deduced context (14.8.2.5), the type of that parameter pack is never deduced.

Args... erscheint in einem nicht abgeleitet Kontext, da aus [temp .deduct.type]:

The non-deduced contexts are: [...] A function parameter pack that does not occur at the end of the parameter-declaration-list.

so durch den genauen Wortlaut der Norm, Args... darf nicht geschlossen werden, so dass Sie es ausdrücklich vorsehen müssen - die nach wie vor in diesem Fall ist wirklich nicht möglich zu fällen T.

Aber in diesem Fall erscheint Args... sowohl in einem abgeleiteten und nicht abgeleiteten Kontext - es soll nichts Args... vom tuple Argumente als {int, float, double} abgeleitet verhindert wird aus werden und dann einfach wieder mit, dass für die variadische Argumente herzuzuleiten und dann am Ende T als int abzuleiten.

Aber dieser vorgeschlagene Prozess würde mit dem typischen Deduktionsprozess in Konflikt geraten, wo wir jedes Parameter/Argument-Paar unabhängig behandeln. In diesem Fall hängt der Abzug auf T sehr stark von Abzug auf Args... aus dem tuple<> Parameter/Argument-Paar.

Wenn Sie einfach den Bestell Flip:

template <class... Args, class T> 
T method(std::tuple<Args...>, T, Args...) { ... } 

dann beide Compiler kompilieren.

Ich habe keine Ahnung, warum gcc das ursprüngliche Beispiel mit Varargs akzeptiert. Das ist eindeutig falsch.

Außerdem, wenn Sie die Template-Parameter Spezifikation Flip, so dass Sie T, ohne Abzug angeben können, dann akzeptiert Klirren aber gcc ablehnt:

template<class T, class... Args> 
T method(std::tuple<Args...>, Args..., T) { 
    return T(); 
} 

int main() { 
    method<int>(std::make_tuple<int>(1), 1, 1); 
} 

Ich würde diese wohlgeformt sein erwarten - Args... kann abgeleitet werden und T muss nicht sein. Die Formulierung "niemals abgeleitet" ist meiner Meinung nach fraglich.

+0

Dies ist weniger raffinierte Antwort, und mehr Bewusstseinsstrom, der diese Art von Annäherungen annimmt - aber hoffentlich macht die Idee dahinter Sinn. – Barry

+1

Die umgedrehte Reihenfolge ist in Ordnung, weil Sie kein Vorlagenparameterpaket mehr in der Mitte der Funktionsparameterliste haben. Das "nie deduced" gilt also nicht mehr, da es nicht mehr in einem nicht-abgeleiteten Zusammenhang erscheint. –

+0

@Johannes wops, das sollte an das andere Beispiel angehängt werden. Der zweite sollte * funktionieren, nein? – Barry

Verwandte Themen