Consider a function object F
taking a constexpr size_t
argument I
struct F
{
template
constex
I call this technique the magic switch.
The most efficient way I know of to do this is to build your own jump table.
// first, index list boilerplate. Does log-depth creation as well
// needed for >1000 magic switches:
template struct indexes {typedef indexes type;};
template struct concat_indexes;
template struct concat_indexes, indexes>{
typedef indexes type;
};
template
using ConcatIndexes = typename concat_indexes::type;
template struct make_indexes:
ConcatIndexes<
typename make_indexes::type,
typename make_indexes::type
>
{};
template struct make_indexes:
indexes<>
{};
template struct make_indexes:
indexes
{};
template
using MakeIndexes = typename make_indexes::type;
// This class exists simply because [](blah){code}... `...` expansion
// support is lacking in many compilers:
template< typename L, typename R, unsigned I >
struct helper_helper {
static R func( L&& l ) { return std::forward(l)(size()); }
};
// the workhorse. Creates an "manual" jump table, then invokes it:
template
auto
dispatch_helper(indexes, L&& l, unsigned i)
-> decltype( std::declval()(size<0>()) )
{
// R is return type:
typedef decltype( std::declval()(size<0>()) ) R;
// F is the function pointer type for our jump table:
typedef R(*F)(L&&);
// the jump table:
static const F table[] = {
helper_helper::func...
};
// invoke at the jump spot:
return table[i]( std::forward(l) );
};
// create an index pack for each index, and invoke the helper to
// create the jump table:
template
auto
dispatch(L&& l, unsigned i)
-> decltype( std::declval()(size<0>()) )
{
return dispatch_helper( MakeIndexes(), std::forward(l), i );
};
which requires some static setup, but is pretty fast when run.
An assert that i
is in bounds may also be useful.
live example