HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppModerate

Improved indices trick

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
indicestrickimproved

Problem

We all know about the indices trick, right? Here's (hopefully) an improved version...

template  struct indices { };

namespace detail
{

template struct catenate_indices;

template 
struct catenate_indices, indices >
{
  using indices_type = indices;
};

template  struct expand_indices;

template 
struct expand_indices::type>
{
  using indices_type = indices;
};

template 
struct expand_indices::type>
{
  static_assert(A  B");
  using indices_type = typename catenate_indices::indices_type,
    typename expand_indices::indices_type
  >::indices_type;
};

}

template 
struct make_indices : detail::expand_indices::indices_type
{
};

template 
struct make_indices_range : detail::expand_indices::indices_type
{
};


Usage:

#include 

#include "utility.hpp"

template 
void show_indices(indices)
{
  [](...){}((((::std::cout ());

  return 0;
}


Any suggestions?

Solution

You can get rid of the ` header by replacing your std::enable_if by a bool template specialization:

template 
struct expand_indices_impl;

template 
struct expand_indices:
    expand_indices_impl
{};

template 
struct expand_indices_impl
{
    using indices_type = indices;
};

template 
struct expand_indices_impl
{
    static_assert(A  B");
    using indices_type = typename catenate_indices::indices_type,
        typename expand_indices::indices_type
    >::indices_type;
};


Moreover, in C++ (and many other programming languages, see Python
range for example), ranges tend to have the end-exclusive form [begin, end); therefore, make_indices_range should contain the indices from 3 to 8, and not from 3 to 9. It is easy to alter the behaviour:

template 
struct make_indices:
    detail::expand_indices::indices_type
{};

template 
struct make_indices_range:
    detail::expand_indices::indices_type
{};


As proposed in the comments,
make_indices_range also needs to provide an empty range when A == B`:

template 
struct make_indices_range:
    indices<>
{};

Code Snippets

template <::std::size_t, ::std::size_t, bool>
struct expand_indices_impl;

template <::std::size_t A, ::std::size_t B>
struct expand_indices:
    expand_indices_impl<A, B, A==B>
{};

template <::std::size_t A, ::std::size_t B>
struct expand_indices_impl<A, B, true>
{
    using indices_type = indices<A>;
};

template <::std::size_t A, ::std::size_t B>
struct expand_indices_impl<A, B, false>
{
    static_assert(A < B, "A > B");
    using indices_type = typename catenate_indices<
        typename expand_indices<A, (A + B) / 2>::indices_type,
        typename expand_indices<(A + B) / 2 + 1, B>::indices_type
    >::indices_type;
};
template <::std::size_t A>
struct make_indices:
    detail::expand_indices<0, A-1>::indices_type
{};

template <::std::size_t A, ::std::size_t B>
struct make_indices_range:
    detail::expand_indices<A, B-1>::indices_type
{};
template <::std::size_t A>
struct make_indices_range<A, A>:
    indices<>
{};

Context

StackExchange Code Review Q#39648, answer score: 11

Revisions (0)

No revisions yet.