Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specifying a member function as a callback in C++11

Tags:

c++

c++11

lambda

I have the following:

typedef std::function<bool (const std::string&)> SomethingCoolCb;

class ClassA
{
public:
    void OnSomethingCool(const SomethingCoolCb& cb)
    {
        _cb = cb;
    }

private:
    SomethingCoolCb _cb;
};

class ClassB
{
public:
    ClassB();
    bool Juggle(const std::string& arg);

private:
    ClassA _obj;
};

and I want to specify the ClassB::Juggle() member function as the callback to ClassB::_obj. Would the proper way to do that in C++11 be (in ClassB's constructor):

ClassB::ClassB()
{
    _obj.OnDoSomethingCool(
        [&](const std::string& arg) -> bool
        {
            return Juggle(arg);
        });
}

From what I understand, the compiler will make a std::function object out of the above lambda code. So when the callback gets invoked, it'll call the std::function::operator() member and then it'll invoke ClassB::Juggle() instead of invoking ClassB::Juggle() directly. Unless I'm mistaken about what happens under the covers, that all seems to be a little inefficient. Is there a better way?

like image 964
Arcadio Alivio Sincero Avatar asked May 07 '12 14:05

Arcadio Alivio Sincero


1 Answers

Only use std::function if you really need polymorphic functions. Otherwise make it a template.

To adapt a member function to a functor use std::mem_fn and then bind an object to the first argument, the resulting functor can serve as your callback.

Sample:

#include <string>
#include <functional>

template<typename F>
class ClassA
{
public:
    ClassA(F f) : _cb(f) {}

private:
    F _cb;
};

class ClassB
{
public:
    ClassB() 
  : _obj(std::bind(&ClassB::Juggle, this, 
                   std::placeholders::_1)) 
  {}
  bool Juggle(const std::string& arg) {return true;}
private:
    ClassA<decltype(std::bind(
                      std::declval<bool (ClassB::*)(const std::string&)>()
                      , std::declval<ClassB*>()
                      , std::placeholders::_1
                      ) ) > _obj;
};

int main()
{
  ClassB b;
  return 0;
}

This side-steps the cost of function at the cost of being horribly ugly.

like image 102
pmr Avatar answered Oct 13 '22 23:10

pmr