For example lets say you have a table of of idents and related actions. 2 possible solution are
* Populate an array with function pointers.
* Generate a switch statement with marcos..
But c++11 has opened a new and what seems to flexible possibility: The ability to use a variaditic template to generated a reduction tree. This seems to have some very interesting possibilities.
* The redux tree can have its action templated... (But I seemed to have a compiler bug that stops it working)
* Its not locked into a single function signature a "Param..." argument pack gives it the flexibility to adapt on both entry and exit of the selection tree.
* good use of inlining lets the tree flatten out and the compiler gets to hit it with opt routines like the macro generated select version.
#include <iostream>
#include <cstring>
// -----------------------------------------------
// IDs
// -----------------------------------------------
enum {
UNKNOWN = 0,
MIN_TAG = UNKNOWN,
INT,
FLOAT,
MAX_TAG
};
// -----------------------------------------------
// ID -> Type translation trait
// -----------------------------------------------
template <int Tag> struct Trait {};
template <> struct Trait<UNKNOWN>
{
typedef void Type;
static const char* id() { return "unknown"; }
};
template <> struct Trait<INT>
{
typedef int Type;
static const char* id() { return "int"; }
};
template <> struct Trait<FLOAT>
{
typedef float Type;
static const char* id() { return "float"; }
};
// -----------------------------------------------
// Execution point
// -----------------------------------------------
template <int I>
void function(char* data)
{
typename Trait<I>::Type value =
(*static_cast<typename Trait<I>::Type*>(
static_cast<void*>(data)));
std::cout
<< " type:" << Trait<I>::id()
<< " value:" << value
<< "\n";
}
template <>
void function<UNKNOWN>(char* data)
{
std::cout
<< " unknown type number given!"
<< "\n";
}
template <>
void function<MAX_TAG>(char* data) { function<UNKNOWN>(data); }
struct DoAction
{
template <int I, typename... Params>
static void call(Params... params)
{
function<I>(params...);
}
};
// -----------------------------------------------
// SelectTree: runtime -> complie time selector
// -----------------------------------------------
template <typename Action, int min, int max>
struct SelectTree
{
enum { mid = (max+min)/2 };
template <typename... Params>
static void call(int i, Params... params)
{
if (i <= mid) SelectTree<Action,min ,mid>::call(i, params...);
else SelectTree<Action,mid+1,max>::call(i, params...);
}
};
template <typename Action, int value>
struct SelectTree<Action, value, value>
{
template <typename... Params>
static void call(int i, Params... params)
{
//Action::call<value>(params...); // compiler bug!
DoAction::call<value>(params...);
}
};
// -----------------------------------------------
// MAIN
// -----------------------------------------------
int main()
{
float x = 1.0;
char data[4];
std::memcpy(data, &x, sizeof(x));
int sel = 3;
std::cin >> sel;
SelectTree<DoAction,MIN_TAG,MAX_TAG>::call(sel, data);
}
the output looks like
$ a.exe 1 type:int value:1065353216 $ a.exe 2 type:float value:1 $ a.exe -2 unknown type number given! $ a.exe 0 unknown type number given! $ a.exe 123213 unknown type number given!