0

In my code, I have several class, each with different methods. For example:

class A {
public:
    int sum(int a, int b);
    bool isScalable(double d);
}

class B {
public:
    std:string ownerName();
}

My aim is to create a map of all the function names as below

std::map<std::string, FnPtr> myMap;

// Add the newly implemented function to this map
myMap["sum"] = &A::sum;
myMap["isScalable"] = &A::isScalable;
myMap["myMap"] = &B::myMap;

The issue is I am not aware how I can define FnPtr. Can you please help me out.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
Jis
  • 127
  • 2
  • 12
  • 1
    What are you trying to achieve? You could use `void *` as the type and cast it as necessary, but this is generally a bad idea. There are probably better approaches to solving your underlying problem. – Benny K Aug 06 '20 at 07:20
  • @BennyK: I want to map each function to a string. This is done as there a message from outside the application in string format and I need to call the function according to the string. For eg. To call sum(10,15), the message received is "sum 10 15" – Jis Aug 06 '20 at 07:30
  • 1
    See: [this question](https://stackoverflow.com/questions/45715219/store-functions-with-different-signatures-in-a-map). You probably *don't* want to do this, it's incredibly brittle to call any of these functions. – Caleth Aug 06 '20 at 07:31
  • Hard to think of a reasonable scenario where this would be solving something – OrenIshShalom Aug 06 '20 at 07:33
  • Just use a switch case on the first word instead. Switch should be at least as fast as std::map. – user202729 Aug 06 '20 at 07:35
  • From the syntax you proposed (`A::sum`) it seems like you want to call methods rather than functions. See [this](https://stackoverflow.com/questions/1485983/calling-c-class-methods-via-a-function-pointer) for how to do that. Let me know if my assumption is incorrect. – chakaz Aug 06 '20 at 07:38

1 Answers1

1

As comments suggest, it is unlikely you really want to do this.

Assuming that you do, however - perhaps you should reconsider whether C++ is the right language for the task. Another language which has better runtime reflection facility might be more appropriate; perhaps an interpreted language like Python or Perl. Those are typically much more convenient when you need to look up class methods by name at runtime.

If it has to be C++, then perhaps you should relax the class structure somewhat. Use a single class for both A's and B's (lets call it MyCommonObj); and have the class hold a map of strings to function pointers. As for these functions' signatures - It's probably a good idea not to make the member functions, but freestanding ones. In that case, perhaps your function pointer type would be:

using generic_function = std::any (*)(std::vector<std::any>);

That's pretty generic - for storage and for invocation. If you have this map, you can easily look up your function name and pass the arguments. However, you might need to also keep additional information about what type your arguments should be, otherwise you'll always be passing strings. ... which is also an option, I suppose:

using generic_function = std::any (*)(std::vector<std::string>);

Now if the A and B members in your example are really non-static like you listed them, i.e. they use instance fields, then these generic functions must also always take a reference or pointer to an instance of MyCommonObj:

using generic_function = std::any (*)(MyCommonObj&, std::vector<std::string>);

Finally, note that code using this type, and run-time lookup of function names etc - will not be very performant.


If you're not using C++17 and don't have access to std::any, you can either:

  • Use boost::any from the Boost libraries.
  • Use an any-emulator library (which exist on GitHub)
  • Use a union of all the types you actually use, e.g. union {int i; double d;} - but then you'll need to protect yourself against passing values of the wrong type.
einpoklum
  • 118,144
  • 57
  • 340
  • 684