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!
No comments:
Post a Comment