Praveen
Praveen

Reputation: 9335

Partial class template specialization c++11

I am trying to compile the below code, but I am getting the error:

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
}

How can I create partial template class object?

Upvotes: 2

Views: 296

Answers (2)

TartanLlama
TartanLlama

Reputation: 65580

If you want the ability to specify start before end, but also to have a default argument for start you could do something like this:

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

This has exactly the usage which you desire, like this:

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

Upvotes: 4

songyuanyao
songyuanyao

Reputation: 172864

You need to specify all the template arguments according to the primary template's declaration, then which one selected will be determined according to the template arguments.

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

If you want to specify fewer template arguments you might want 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

Note that I changed the order of the template parameters, because if the default argument is specified for a template parameter, each subsequent template parameter must have a default argument too.

Upvotes: 4

Related Questions