Note that there are some explanatory texts on larger screens.

plurals
  1. PORecursive Template List instead of hard coded switch statement with key/id based search
    text
    copied!<p>I am reading/writing a structure using C++ (vc2008) whose type changes based on an ID flag obviously at runtime. The creation of the correct type and/or reading and writing would require a switch. The closest existing example is <a href="https://stackoverflow.com/questions/5650199/using-template-instead-of-switch">Using template instead of switch</a> but this does not allow the type to be specified at run-time. To avoid creating the same switch in multiple places I have been investigating the use of recursive templates to overcome this issue. This is my first time with these so there may be some major improvements that can be done to the code example! </p> <p>Below is a working example. As you will see in 'main()' the type id used is a variable int which can be set to any runtime value. Calling a function on TypeList&lt;> will recurse through the types until it reaches a matching ID or a void type.</p> <pre><code>#include &lt;stdio.h&gt; #include &lt;iostream&gt; //Base type struct Base { //NOTE: The virtual destructor can be added to aid with debugging //virtual ~Base(){} friend std::ostream&amp; operator &lt;&lt; ( std::ostream&amp; stream, const Base&amp; rhs ) { return stream &lt;&lt; "Base"; } }; struct A : Base { friend std::ostream&amp; operator &lt;&lt; ( std::ostream&amp; stream, const A&amp; rhs ) { return stream &lt;&lt; "A"; } }; struct B : Base { friend std::ostream&amp; operator &lt;&lt; ( std::ostream&amp; stream, const B&amp; rhs ) { return stream &lt;&lt; "B"; } }; struct C : Base { friend std::ostream&amp; operator &lt;&lt; ( std::ostream&amp; stream, const C&amp; rhs ) { return stream &lt;&lt; "C"; } }; //Recursive template type // - If the ID/key does not match the next type is checked and so on template &lt; unsigned int kID, typename _Type, typename _TNext &gt; struct TypeList { typedef _Type Type; typedef typename _TNext::Base Base; static Base* doNew( unsigned int id ) { return id == kID ? new _Type() : (Base*)_TNext::doNew(id); } static void doDelete(unsigned int id, Base* rhs ) { id == kID ? delete (_Type*)rhs : _TNext::doDelete(id, rhs ); } static std::ostream&amp; doWrite( unsigned int id, std::ostream&amp; stream, const Base* rhs ) { return id == kID ? stream &lt;&lt; (*(const _Type*)rhs) : _TNext::doWrite(id, stream, rhs); } }; //Specialise the 'void' case to terminate the list // TODO; this doesn't seem as elegant as possible!? How can we separate the logic from the functionality better... template &lt; unsigned int kID, typename _Type &gt; struct TypeList&lt;kID, _Type, void&gt; { typedef _Type Type; typedef _Type Base; static _Type* doNew( unsigned int id ) { return id == kID ? new _Type() :0; } static void doDelete(unsigned int id, _Type* rhs ) { if ( id == kID ) delete rhs; } static std::ostream&amp; doWrite( unsigned int id, std::ostream&amp; stream, const _Type* rhs ) { return id == kID ? stream &lt;&lt; (*(const _Type*)rhs) : stream; } }; // ID values used to identify the different structure types enum eID { ID_A, ID_B, ID_C, }; //Create our ID and Type list typedef TypeList&lt; ID_A, A, TypeList&lt; ID_B, B, TypeList&lt; ID_C, C, TypeList&lt; -1 , Base, void&gt; &gt; &gt; &gt; TypesList; int _tmain(int argc, _TCHAR* argv[]) { eID type = ID_C; //, We are dealing with a type of 'C' Base* newInst = TypesList::doNew( type ); //Create a new C TypesList::doWrite( type, std::cout, newInst ); //Write 'C' to the console TypesList::doDelete( type, newInst ); //Delete C return 0; } </code></pre> <p>What are peoples views on this and other/better ways to do this? Mainly is there a way to nicely separate the logic from the functionality of the class to save having duplicated code in the TypeList&lt;,,_Type> and the TypeList&lt;,,void> instantiations.</p> <p>EDIT: The solution preferably requires no run-time setup to 'add' types to a lookup or the likes.</p> <p>Cheers, Craig</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload