Search code examples
c++functionc++11lambdafunctor

Can I have an array of lambda pointers in order to hold functions with different types of arguments/return values?


Let's assume I have a class with two member functions:

#include <string>
#include <vector>

using namespace std;

class MyClass{
  MyClass(){
    MyCommandServer server;
    server.addToCollection(&[](string a)->string{return helloWorld();});
    server.addToCollection(&[](string a)->string{return to_string(add(stoi(a[0]),stoi(a[1])));});

    while(true){
      server.pollForCommand();
      doSomethingElse();
    }
  }

  string helloWorld(){
    return "Hello World!";
  }

  int add(int a, int b){
    return a+b;
  }
};

And another Class that is instantiated in the first one:

typedef string (*MyFunctionPointer)(string);

class MyCommandServer{
  MyCommandServer(){}

  void addToCollection(MyFunctionPointer ptr){
    functionCollection.push_back(ptr);
  }

  void pollForCommand(){
    string newCommand = checkForCommand(&args);
    if(newCommand.size()&&isValidCommand(newCommand[0])){
      sendResponseToClient(functionCollection[newCommand[0]](newCommand.substr(1)));
    }
  }

  string checkForCommand();
  bool isValidCommand(char);
  void sendResponseToClient(string);
  vector<MyFunctionPointer> functionCollection;
};

How would I go about passing my first two methods to addToCollection(MyFunctionPointer)? I was wondering if something along the lines of the example was possible. My goal is to have a way to call the functions of MyClass with only their index in the container, and figuring out how to use the provided arguments, if at all, by means of the supplied lambda function. This is supposed to enable a Command Server class, where I get a char as the said index and the arguments, if any, as a string via UDP.

However, the compiler won't let me pass a reference to a lambda..

Making a switch-case statement in the MyServerClass, where I manually enter the code I put in the lambdas in the example, is not feasible since the Server class does not know about its parents methods.

Is something similar to the example given possible?

Sorry if the post is not up to standards, its my first on here.

Thanks for your help!


Solution

  • The reason your lambda approach does not work is that you can only turn a lambda into a function pointer if the lambda has no captures. However, to use/wrap a (non-static) member function in a lambda, the lambda must capture (store) the specific object instance to call that member function on (this), and function pointers cannot have (non-global) stored state like that. If you add this to the capture list, then the lambdas themselves are valid but can no longer decay to a function pointer.

    std::function allows you to store arbitrary callable objects - even those with captures. They also tend to be more readable (and higher level) than function pointers.

    using MyFunctionType = std::function<std::string(std::string)>;
    
    class MyCommandServer
    {
      void addToCollection(MyFunctionType fnc){
        functionCollection.push_back(fnc);
      }
    
      // ...
    
      vector<MyFunctionType> functionCollection;
    }
    

    Now MyCommandServer can accept and store your lambdas (if you pass them by value), since they can be called with a string argument and return a string.