2016-04-01 11 views
2

Ich versuche, den folgenden Code zu kompilieren, aber ich bin immer die Fehlermeldung:Partielle Klassen-Template Spezialisierung C++ 11

wrong number of template arguments

template<int start, int end, int step> 
struct range{}; 

template<int start, int end> 
struct range<start, end, 1>{}; 

template<int end> 
struct range<0, end, 1>{}; 

int main() { 
    auto r1 = range<0, 5, 2>{}; 
    auto r2 = range<5, 15>{}; //error: wrong number of template arguments 
    auto r3 = range<10>{}; //error: wrong number of template arguments 
} 

Wie kann ich teilweise Template-Klasse-Objekt erstellen?

+3

versuchen Sie, machen '0' und '1' Standardargumente sein? – TartanLlama

+2

Die Vorlagenspezialisierung gibt an, wie sie sich mit bestimmten Parametern verhalten soll, ändert jedoch nicht, wie sie _instantiiert_ wird. Dazu wird immer die erste Template-Deklaration verwendet. – StenSoft

Antwort

4

Wenn Sie wollen, dass die Fähigkeit start vor end, zu spezifizieren, sondern auch ein Standardargument haben für start Sie so etwas tun könnte:

template <int... Args> 
struct range { 
    static_assert(sizeof...(Args) > 0 && sizeof...(Args) <= 3, 
        "Must pass 1-3 args"); 

    using ArgPack = std::tuple<std::integral_constant<int, Args>...>; 

    template <int Size, typename Then, typename Else> 
    using select_value = typename std::conditional_t< 
     (sizeof...(Args) > Size), Then, Else 
    >::type; 

    static constexpr int start = select_value<1, 
     std::tuple_element<0, ArgPack>, std::integral_constant<int,0> 
    >::value; 

    static constexpr int end = select_value<1, 
     std::tuple_element<1, ArgPack>, std::tuple_element<0, ArgPack> 
    >::value; 

    static constexpr int step = select_value<2, 
     std::tuple_element<2, ArgPack>, std::integral_constant<int,1> 
    >::value; 
}; 

Dies hat genau die Verwendung, die Sie wünschen, wie folgt aus:

int main() 
{ 
    using a = range<1,1,2>; 
    static_assert(a::start == 1 && a::end == 1 && a::step == 2, "wat"); 

    using b = range<1,1>; 
    static_assert(b::start == 1 && b::end == 1 && b::step == 1, "wat"); 

    using c = range<3>; 
    static_assert(c::start == 0 && c::end == 3 && c::step == 1, "wat"); 
} 

Live Demo

4

Sie müssen alle Vorlagenargumente gemäß der Deklaration der primären Vorlage angeben, und dann wird die ausgewählte Vorlage anhand der Vorlagenargumente bestimmt.

auto r1 = range<0, 5, 2>{}; // the primary template 
auto r2 = range<5, 15, 1>{}; // the 1st partial specified template 
auto r3 = range<0, 10, 1>{}; // the 2nd partial specified template 

Wenn Sie Sie weniger Vorlage Argumente angeben möchten vielleicht wollen default template arguments:

template<int end, int start = 0, int step = 1> 
struct range{}; 

auto r1 = range<5, 0, 2>{}; // end->5, start->0, step->2 
auto r2 = range<15, 5>{}; // end->15, start->5, step->1 
auto r3 = range<10>{};  // end->10, start->0, step->1 

Bitte beachte, dass ich die Reihenfolge der Template-Parameter geändert, denn wenn das Standardargument für einen Template-Parameter angegeben wird, Jeder nachfolgende Vorlagenparameter muss ebenfalls ein Standardargument haben.