Частичная специализация шаблона класса C++11

Я пытаюсь скомпилировать код ниже, но я получаю сообщение об ошибке:

неверное количество аргументов шаблона

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
}

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

2 ответа

Решение

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

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

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

Если вы хотите указать меньше аргументов шаблона, вам могут потребоваться аргументы шаблона по умолчанию:

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

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

Другие вопросы по тегам