Search code examples
c++lambdacallbackinvokefunctor

How to store a functor for later invocation in C++


This question might be naïve, if so please forgive me as I am learning.

Please consider the following C++-like pseudo code:

#include <iostream>
#include <string>
#include <functional>


struct A{
    bool doSomething(int in){
        std::cout<<"SOMETHING WAS DONE THAT DAY: "<<in<<std::endl;
        return true;
    }
};

struct B{
    std::function executor;

    void setExecutor(std::function f){
        executor=f;
    }

    bool doSomethingLater(int in){
        return executor(in);
    }
};

static bool yoloFunction(int in){
    std::cout<<"LIVING LA VIDA LOCA: "<<in<<std::endl;
    return false;
}


int main()
{
  A myExecutor;
  B lazyAss;

  // Storing member function for later invocation
  lazyAss.setExecutor(&myExecutor::doSomething);
  bool result_1 = lazyAss.doSomethingLater(1337);
  std::cout<<"The first result is "<<result_1<<std::endl;

  // Storing regular function for later invocation
  lazyAss.setExecutor(&yoloFunction);
  bool result_3 = lazyAss.doSomethingLater(42);
  std::cout<<"The second result is "<<result_2<<std::endl;

  // Storing lambda function for later invocation
  lazyAss.setExecutor([=](int in){
    std::cout<<"P- P- P- POKERFACE!: "<<in<<std::endl;
    return true;
  });
  bool result_3 = lazyAss.doSomethingLater(666);
  std::cout<<"The third result is "<<result_3<<std::endl;

}

It should illustrate what I am trying to accomplish, namely to store a callback of some kind for later invocation.

So how would I go about doing this in modern C++ in the simplest way possible, without using boost or other non-standard dependencies?

What options and caveats are there?

Things to note are that the signature of the callback is known in advance and will not change.

Also the callback I want to store may be of different forms like stand alone function, member function or lambda.


Solution

  • Modify struct B like this:

    struct B {
        std::function<bool(int)> executor;
    
        void setExecutor(std::function<bool(int)> f) {
            executor = f;
        }
    
        bool doSomethingLater(int in) {
            return executor(in);
        }
    };
    

    In main(), use a lambda to pass the member function as parameter like this:

    lazyAss.setExecutor([&](int i)->bool { return myExecutor.doSomething(i); });