Search code examples
c++qtcompile-timeqt4.8pre-compilation

Mechanism for extensible conditional statement


I have these lines in my code:

//lines in mycode.c++
  QString str = "...some id...";

       if( str == "int")
           foo< int>()
  else if( str == "QString")
           foo< QString>()
       ...

I need to create a mechanism to include custom types in this conditional statement. So, any programmer can register his class and his implementation of foo templated function.

I imagine it like this:

//A.h -- custom class
class A { };

template< >
  void foo< A>() { ... };

DECL( A, "A"); //macro to declare class

I want conditional statement in mycode.c++ that would automatically take in account declaration of class A, so it will have additional lines:

else if( str == "A")
    foo< A>()

I could have this effect like this:

//common.h
  void process_id( QString str) {
       if( str == "int")
           foo< int>()
  else if( str == "QString")
           foo< QString>()
       ...
  else if( str == "A") //this lines programmer put manually
           foo< A>();
  }

//mycode.c++
  #include "common.h"

  QString str = "some_id";

  process_id( str);

but what if programmer forgets to edit common.h file?

I thought, maybe to use C-macros system, or somehow Qt-precompilation. Is it possible?


Solution

  • I would do something like this:

    void process_id(QString const & str) 
    {
       auto it =  g_actions.find(str);
       if ( it != g_actions.end() )  
             (it->second)(); //invoke action
    }
    

    And the framework to support the above is implemented as:

     using action_t = std::function<void()>;
    
     std::map<QString, action_t>  g_actions; //map of actions!
    
    #define VAR_NAME(x)       _ ## x
    #define DEFINE_VAR(x)  VAR_NAME(x)
    #define REGISTER(type) char DEFINE_VAR(__LINE__) = (g_actions[#type] = &foo<type>,0)
    

    Now you could register any class as:

     //these lines can be at namespace level as well!
     REGISTER(A);
     REGISTER(B);
     REGISTER(C);
    

    And then call process_id() as:

    process_id("A"); //invoke foo<A>();
    process_id("B"); //invoke foo<B>();
    

    Hope that helps.

    See this online demo.