2013-08-11 5 views
10

Der folgende CodeTeil Spezialisierung für variadische Vorlage muss zuerst nicht-variadische Template-Parameter

#include <iostream> 
#include <utility> 

template<typename F, typename... T> 
struct Wrapper{ }; 

template<typename T> 
struct is_wrapper : std::false_type {}; 

template<typename... T> 
struct is_wrapper<Wrapper<T...>> : std::true_type {}; 

//template<typename F, typename... T> 
//struct is_wrapper<Wrapper<F, T...>> : std::true_type {}; 

int main() 
{ 
    Wrapper<int, double> w; 

    std::cout << is_wrapper<decltype(w)>::value << std::endl; 
} 

druckt 0. Wenn man jedoch die beiden Linien in der Mitte uncomments druckt er 1.

Warum doesn‘ t es immer 1 drucken? Sollte die zweite Teilspezialisierung nicht auch den Fall abdecken, der offenbar nur von der dritten (kommentierten) Teilspezialisierung abgedeckt wird?

Antwort

1

Der Code sollte tatsächlich der Teilspezialisierung entsprechen; Der Standard hat dies nie wirklich verboten, aber Compiler haben eine Weile gebraucht, um variantenbasierte Vorlagen und deren Abzug richtig zu implementieren. GCC entspricht seit 4.9.0 und Clang ab 3.6. Der relevante Fehlerbericht für Clang ist #22191 (ich kann jedoch keine GCCs finden).

0

Normalerweise, wenn ich Templates schreibe, die spezialisiert sind, verwende ich zuerst eine Forward-Deklaration und deklariere die Fälle als Spezialisierungen. In Ihrem Fall verstehe ich, dass Sie versuchen, eine variadische Vorlage ohne den leeren Fall zu schreiben (dh eine variadische Vorlage, die mindestens einen Typ haben könnte).

Ihr Code überraschte mich, weil ich denke, dass Sie richtig sind, passt die volle variadic Spezialisierung Ihres Merkmals den Loch Fällen ... Zuerst habe ich versucht, eine Vorwärtsdeklaration Ihrer Merkmalklasse zu verwenden, und definieren Sie NUR die volle Variadic Spezialisierung (Wenn also der Parameter des Merkmals keine Wrapper Instanz ist, schlägt die Kompilierung fehl). Und das ist genau das, was hat aufgetreten, mich wieder enttäuschend:

#include <iostream> 
#include <utility> 

template<typename F , typename... T> 
struct Wrapper {}; 

template<typename T> 
struct is_wrapper; 

//template<typename T> 
//struct is_wrapper : std::false_type {}; 

template<typename... T> 
struct is_wrapper<Wrapper<T...>> : std::true_type {}; 

//template<typename F, typename... T> 
//struct is_wrapper<Wrapper<F, T...>> : std::true_type {}; 

using my_wrapper_type = Wrapper<int,double>; 

int main() 
{ 
    std::cout << std::boolalpha << is_wrapper<my_wrapper_type>::value << std::endl; 
}//"Invalid use of incomplete type" ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

Schließlich habe ich versucht, mit der Forward-Deklaration Methode in der Wrapper Klasse. Und überraschend, dass es funktioniert:

#include <iostream> 
#include <utility> 

template<typename... T> 
struct Wrapper; 

template<typename F, typename... T> 
struct Wrapper<F,T...>{ }; 


template<typename T> 
struct is_wrapper : std::false_type {}; 

template<typename... T> 
struct is_wrapper<Wrapper<T...>> : std::true_type {}; 

//template<typename F, typename... T> 
//struct is_wrapper<Wrapper<F, T...>> : std::true_type {}; 


using my_wrapper_type = Wrapper<int,double>; 

int main() 
{ 
    std::cout << std::boolalpha << is_wrapper<my_wrapper_type>::value << std::endl; 
} 

Diese Drucke:

wahr

Here ist der Code bei ideone läuft.

Mit freundlichen Grüßen, ich verstehe nicht, warum Ihr Code fehlschlägt und meins funktioniert. Es ist ein Compiler-Bug, oder gibt es etwas, was uns fehlt? Ich weiß es nicht.

+0

Der Unterschied ist die Anzahl der Template-Parameter für die Klassenvorlage 'Wrapper'. Ihre (zweite) Version hat nur einen Template-Parameter, während die OP-Version zwei Parameter hat. Ihre partielle Spezialisierung 'struct Wrapper ' ändert das nicht. – dyp

+0

@DyP OK, aber wenn Sie eine Vorlage mit zwei Parametern haben (Ein normaler Vorlagenparameter und ein variadischer Vorlagenparameter) und Sie ein Variadic-Paket an diese Vorlage übergeben, muss das Variadic-Paket nicht entsprechend dem ersten normalen Parameter erweitert werden. und der zweite Parameter (Variadic Parameter)?Das ist, was ich nicht verstehe, warum das Paket nicht auf diese Weise erweitert wird. – Manu343726

+0

Ich versuche immer noch herauszufinden, wo (und warum) der Standard verbietet, dass die Teilspezialisierung in diesem Fall mit dem Parameter-Paket übereinstimmt. Schätze, es ist irgendwo um [temp.educt.type]/9 herum. (Pack-Erweiterung unterscheidet sich von der Ableitung.) – dyp

0

Wenn ich gut Ihr Problem zu verstehen, es ist nur eine Spezialisierung Priorität,

is_wrapper<decltype(w)> 

Kann durch 2-Vorlage spezialisiert werden:

template<typename T> // exact specialization 
template<typename... T> // variadic specialization with one parameter 

In diesem Fall Compiler Priorität wählt die genaue Spezialisierung und so template ist in Ihrem Fall niemals instatiziert.

+0

Das ist falsch. Partielle Spezialisierungen werden immer primären Templates vorgezogen (und müssen auf jeden Fall spezialisierter sein), siehe § 14.5.5.1. – Columbo

Verwandte Themen