Reputation: 9335
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
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");
}
Upvotes: 4
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