0

I am trying to write a program that will execute a function based on a string I fetch from a database. Basically what I do is:

// Create an enum
enum AFunc{
 invalidFunction,
 function2,
 function3
}

// have a class handling the functions
struct A
{
  static AFunc resolveStringToFunction(std::string) {...}

  template<int T>
  void execute(...)
  {
     // this may not be called = invalidFunction
  }

  template<>
  void execute<1> (...)
  { 
     // do stuff = function1
  }

  template<>
  void execute<2> (...)
  { 
     // do stuff = function2
  }
};

In my application i do this:

A a;
std::string funcString = getFromDatabase (...) // Not really, but this is abstract
const AFunc funcType   = A::resolveStringToFunction(funcString);

a.execute<funcType>(...);

The problem here is that the compiler does not accept the dynamic calling of a template function, because (as I understood it) it needs to know which function is called by compile time.

Is there any way around this?

Is there a better solution to this problem? Maybe a design pattern?

Flo Win
  • 154
  • 10
  • 6
    `std::unordered_map>`. I call it the "hash table from strings to functions" design pattern. – The Paramagnetic Croissant Sep 29 '15 at 08:42
  • (also, if you don't know the names of the functions at compile-time, then you can always `dlopen()` and `dlsym()`. Or the equivalents thereof if you're running a stupid non-POSIX system like Windows. Might as well look up `extern "C"` linkage on the way.) – The Paramagnetic Croissant Sep 29 '15 at 08:48
  • @TheParamagneticCroissant Yeah that's a solution i already tried but i thought "there has to be a better way" as i can't implement an interface with the functions - so the footprint of the static functions could vary and i would run into problems on runtime and not on compiletime, right? – Flo Win Sep 29 '15 at 08:55
  • if the types of your functions are heterogenous, then you will have to store the type as well and resort to plain old function pointers, casted to the appropriate type and invoked in different manners. There's no way around that – since C++ doesn't have run-time reflection. – The Paramagnetic Croissant Sep 29 '15 at 08:58
  • okay, thanks! i'll post my solution as the answer when i'm done implementing it. – Flo Win Sep 29 '15 at 09:01
  • 2
    @TheParamagneticCroissant: And it sounded like good advice until you started calling it a "design pattern"... – Kerrek SB Sep 29 '15 at 09:17
  • @TheParamagneticCroissant I added the example code, it compiles, how is the style? – Flo Win Sep 29 '15 at 09:39
  • @FloWin It's fine. I'd use an `unordered_map` (since the order seems to have no significance) and an initializer list (in order not to have to `boost::assign`), though. – The Paramagnetic Croissant Sep 29 '15 at 09:45

1 Answers1

0
namespace afunc // dont pollute global namespace
{

typedef std::function<void(...)> aFunc;
static function1(...)
{    
  // do stuff
}

static function2(...)
{    
  // do stuff
}

const std::unordered_map<std::string, aFunc> functions (
 {{"function1", &function1},{"function2", &function2}} ); // afunc

And it is called by the following code:

std::string funcString = getFromDatabase (...) // Not really, but this is abstract
afunc::functions.at(funcString)(...) // at because the map is const, so it's even threadsafe
Flo Win
  • 154
  • 10