Let me please consider the following synthetic example:
inline int fun2(int x) {
return x;
}
inline int fun2(double x) {
return 0;
}
inline int fu
Ok, I rewrote my answer. This gives a different approach to what TartanLlama and also what I suggested before. This meets your complexity requirement and doesn't use function pointers so everything is inlineable.
Edit: Much thanks to Yakk for pointing out a quite significant optimization (for the compile-time template recursion depth required) in comments
Basically I make a binary tree of the types / function handlers using templates, and implement the binary search manually.
It might be possible to do this more cleanly using either mpl or boost::fusion, but this implementation is self-contained anyways.
It definitely meets your requirements, that the functions are inlineable and runtime look up is O(log n) in the number of types in the tuple.
Here's the complete listing:
#include
#include
#include
#include
using std::size_t;
// Basic typelist object
template
struct TypeList{
static const int size = sizeof...(TL);
};
// Metafunction Concat: Concatenate two typelists
template
struct Concat;
template
struct Concat , TypeList> {
typedef TypeList type;
};
template
using Concat_t = typename Concat::type;
// Metafunction First: Get first type from a typelist
template
struct First;
template
struct First > {
typedef T type;
};
template
using First_t = typename First::type;
// Metafunction Split: Split a typelist at a particular index
template
struct Split;
template
struct Split> {
private:
typedef Split> FirstSplit;
typedef Split SecondSplit;
public:
typedef Concat_t L;
typedef typename SecondSplit::R R;
};
template
struct Split<0, TypeList> {
typedef TypeList<> L;
typedef TypeList R;
};
template
struct Split<1, TypeList> {
typedef TypeList L;
typedef TypeList R;
};
template
struct Split> {
typedef TypeList<> L;
typedef TypeList<> R;
};
// Metafunction Subdivide: Split a typelist into two roughly equal typelists
template
struct Subdivide : Split {};
// Metafunction MakeTree: Make a tree from a typelist
template
struct MakeTree;
/*
template<>
struct MakeTree> {
typedef TypeList<> L;
typedef TypeList<> R;
static const int size = 0;
};*/
template
struct MakeTree> {
typedef TypeList<> L;
typedef TypeList R;
static const int size = R::size;
};
template
struct MakeTree> {
private:
typedef TypeList MyList;
typedef Subdivide MySubdivide;
public:
typedef MakeTree L;
typedef MakeTree R;
static const int size = L::size + R::size;
};
// Typehandler: What our lists will be made of
template
struct type_handler_helper {
typedef int result_type;
typedef T input_type;
typedef result_type (*func_ptr_type)(const input_type &);
};
template::func_ptr_type me>
struct type_handler {
typedef type_handler_helper base;
typedef typename base::func_ptr_type func_ptr_type;
typedef typename base::result_type result_type;
typedef typename base::input_type input_type;
static constexpr func_ptr_type my_func = me;
static result_type apply(const input_type & t) {
return me(t);
}
};
// Binary search implementation
template
struct apply_helper;
template
struct apply_helper {
template
static int apply(const V & v, size_t index) {
assert(index == 0);
return First_t::apply(v);
}
};
template
struct apply_helper {
template
static int apply(const V & v, size_t index) {
if( index >= T::L::size ) {
return apply_helper::apply(v, index - T::L::size);
} else {
return apply_helper::apply(v, index);
}
}
};
// Original functions
inline int fun2(int x) {
return x;
}
inline int fun2(double x) {
return 0;
}
inline int fun2(float x) {
return -1;
}
// Adapted functions
typedef std::tuple tup;
inline int g0(const tup & t) { return fun2(std::get<0>(t)); }
inline int g1(const tup & t) { return fun2(std::get<1>(t)); }
inline int g2(const tup & t) { return fun2(std::get<2>(t)); }
// Registry
typedef TypeList<
type_handler,
type_handler,
type_handler
> registry;
typedef MakeTree jump_table;
int apply(const tup & t, size_t index) {
return apply_helper::apply(t, index);
}
// Demo
int main() {
{
tup t{5, 1.5, 15.5f};
std::cout << apply(t, 0) << std::endl;
std::cout << apply(t, 1) << std::endl;
std::cout << apply(t, 2) << std::endl;
}
{
tup t{10, 1.5, 15.5f};
std::cout << apply(t, 0) << std::endl;
std::cout << apply(t, 1) << std::endl;
std::cout << apply(t, 2) << std::endl;
}
{
tup t{15, 1.5, 15.5f};
std::cout << apply(t, 0) << std::endl;
std::cout << apply(t, 1) << std::endl;
std::cout << apply(t, 2) << std::endl;
}
{
tup t{20, 1.5, 15.5f};
std::cout << apply(t, 0) << std::endl;
std::cout << apply(t, 1) << std::endl;
std::cout << apply(t, 2) << std::endl;
}
}
Live on Coliru: http://coliru.stacked-crooked.com/a/3cfbd4d9ebd3bb3a