2016-04-01 3 views
2

Я пытаюсь скомпилировать код, приведенный ниже, но я получаю сообщение об ошибке:Частичный класс специализация шаблона 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 
} 

Как я могу создать частичный объект класса шаблона?

+3

вы пытаетесь сделать '0' и' 1' быть аргументы по умолчанию? – TartanLlama

+2

Специализация шаблона рассказывает, как он должен _behave_ с определенными параметрами, но не меняет, как он _инстантирован. Для этого всегда используется первое объявление шаблона. – StenSoft

ответ

4

Если вы хотите возможность указать start до того end, но и иметь аргумент по умолчанию для start вы могли бы сделать что-то вроде этого:

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; 
}; 

Это именно использование, которое вы хотите, как это:

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

Необходимо указать все аргументы шаблона в соответствии с объявлением первичного шаблона, после чего выбранный будет определяться в соответствии с аргументами шаблона.

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 

Если вы хотите указать меньше аргументов шаблона вы можете 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 

Обратите внимание, что я изменил порядок параметров шаблона, потому что если аргумент по умолчанию, заданное для параметра шаблона, каждый последующий параметр шаблона также должен иметь аргумент по умолчанию.