From a previous question I got an answer that included some template magic (that to be blunt was mind-boggling (as I could not understand it)).
So I have been trying to achieve the same results (because trying helps me learn).
To make sure I have learn correctly I am putting it here for comment. Hopefully it will also help somebody else (and you never know it may encourage me to write a blog post about it).
Template based ranges (I am sure it has been done to death).
The idea you provide a range that expanded by the template to make writing code easier. So the code I use to test it is working correctly.
template<typename>
struct printNumberRange;
// Only a specialization for my range is implemented.
template<int... N>
struct printNumberRange<Sizes<N...>>
{
static void call()
{
std::vector<int> v {N...};
std::copy(std::begin(v), std::end(v), std::ostream_iterator<int>(std::cout, "\n"));
}
};
// Function to deduce the arguments and
// Call the print correctly.
template<int S, int E>
void printRange()
{
print<typename Range<S,E>::type>::call();
}
int main()
{
// Print the range using a template
printRange<3,8>();
}
Version 1
The template code I started with:
template<int... N>
struct Sizes
{
typedef Sizes<N...> type;
};
template<int C, int P, int... N>
struct GetRange
{
typedef typename GetRange<C-1, P+1, N..., P>::type type;
};
template<int P, int... N>
struct GetRange<0, P, N...>
{
typedef typename Sizes<N..., P>::type type;
};
template<int S, int E>
struct Range
{
typedef typename GetRange<E-S, S>::type type;
};
But it seems the trend nowadays is to use inheritance to get rid of the ugly typedef typename ....
at each level:
Version 2
This should be exactly the same.
But we use inheritance to get the type of the terminal class in the recursion. Personally I find this much harder to read than the previous version. But it is more compact.
template<int... N>
struct Sizes
{
typedef Sizes<N...> type;
};
template<int C, int P, int... N>
struct GetRange: GetRange<C-1, P+1, N..., P>
{};
template<int P, int... N>
struct GetRange<0, P, N...>: Sizes<N...>
{};
template<int S, int E>
struct Range: GetRange<E-S+1, S>
{};
I can specialize printNumberRange
to take a range directly.
template<int S, int E>
struct printNumberRange<Range<S, E>>:
printNumberRange<typename Range<S,E>::type> // Inherits from the version
{}; // That takes a Sizes<int...>
Then the print becomes:
int main()
{
printNumberRange<Range<4,18>>::call();
}
Any comments on the Range stuff or the test harness welcome.