How can I pass a class method as a parameter to another function and later call it, preferably making the variable class method signature explicit?

If I have a class that needs to call a parent class method with a class method as parameter I can do it with std::function + std::bind as shown below:

class A {
    void complexMethod(std::function<void()> variableMethod) {
        // other stuff ...
        variableMethod();
        // some other stuff..
    }
}

class B : public A {
    void myWay() {
        // this and that
    }

    void otherWay() {
        // other and different
    }

    void doingSomething() {
        // Preparing to do something complex.
        complexMethod(std::bind(&B::myWay, this));
    }

    void doingAnotherThing() {
        // Different preparation to do some other complex thing.
        complexMethod(std::bind(&B::otherWay, this));
    }
}

How would I need to change the above code to implement the same thing using templates instead of std::function + std::bind?

And how about lambdas instead of std::function + std::bind? I still want to call B:myWay() and B::otherWay() but using lambdas. I don't want to substitute B:myWay() and B::otherWay() with lambdas.

Is there any implementation technique (one of the above or some other) were I would be able to make variableMethod return type and parameters explicit? How would I do it? Let's say the signature of variableMethod is:

    bool variableMethod(int a, double b);

Which technique is recommended? Why (speed, flexibility, readility...)?


Template + lambda solution:

struct A
{
    template <typename F>
    void runA(F func)
    {
        cout << 1 << endl;
        func();
        cout << 3 << endl;
    }
};

struct B : A
{
    int number = 2;

    void runnable() { cout << number << endl; }

    void runB()
    {
        cout << 0 << endl;
        runA([this]() { runnable(); });
        cout << 4 << endl;
    }
};

int main()
{
    B variable;
    variable.runB();
}

In order to take a function as template parameter, just take in a template type of that function like above. lambdas can be used instead of bind to make things easier (this is passed to lambda captures list).

Explicitly declaring the arguments:

void run_func(std::function<bool(int, double)> func)
{
    bool b = func(10, 10.01);
}

std::function allows you to define your arguement and return types like above.


How would I need to change the above code to implement the same thing using templates instead of std::function + std::bind?

And how about lambdas instead of std::function + std::bind? I still want to call B:myWay() and B::otherWay() but using lambdas. I don't want to substitute B:myWay() and B::otherWay() with lambdas.

You can use a lambda, yes.

Something like [this]() { return myWay(); } that:

  • captures this, and
  • calls a method of the current object.

[Demo]

#include <iostream>  // cout

class A {
protected:
    template <typename F>
    void complexMethod(F&& f) { f(); }
};

class B : public A {
    void myWay() { std::cout << "myWay\n"; }
    void otherWay()  { std::cout << "otherWay\n"; }
public:
    void doingSomething() {
        complexMethod([this]() { return myWay(); });
    }
    void doingAnotherThing() {
        complexMethod([this]() { return otherWay(); });
    }
};

int main() {
    B b{};
    b.doingSomething();
    b.doingAnotherThing();
}

// Outputs:
//
//   myWay
//   otherWay

Is there any implementation technique (one of the above or some other) were I would be able to make variableMethod return type and parameters explicit? How would I do it?

You could use const std::function<bool(int,double)>& f as the parameter receiving a function for complexMethod. And still pass a lambda. Notice though lambdas are now receiving (int i, double d) (it could be (auto i, auto d) as well).

[Demo]

#include <functional>  // function
#include <ios>  // boolalpha
#include <iostream>  // cout

class A {
protected:
    bool complexMethod(const std::function<bool(int,double)>& f, int i, double d)
    { return f(i, d); }
};

class B : public A {
    bool myWay(int a, double b) { return a < static_cast<int>(b); }
    bool otherWay(int a, double b)  { return a*a < static_cast<int>(b); }
public:
    bool doingSomething(int a, double b) {
        return complexMethod([this](int i, double d) {
            return myWay(i, d); }, a, b);
    }
    bool doingAnotherThing(int a, double b) {
        return complexMethod([this](auto i, auto d) {
            return otherWay(i, d); }, a, b);
    }
};

int main() {
    B b{};
    std::cout << std::boolalpha << b.doingSomething(3, 5.5) << "\n";
    std::cout << std::boolalpha << b.doingAnotherThing(3, 5.5) << "\n";
}

// Outputs:
//
//   true
//   false

Notice also the same could be accomplished with templates, although you wouldn't be making the signature explicit.

[Demo]

#include <functional>  // function
#include <ios>  // boolalpha
#include <iostream>  // cout

class A {
protected:
    template <typename F, typename... Args>
    auto complexMethod(F&& f, Args&&... args) -> decltype(f(args...))
    { return f(args...); }
};

class B : public A {
    bool myWay(int a, double b) { return a < static_cast<int>(b); }
    bool otherWay(int a, double b)  { return a*a < static_cast<int>(b); }
public:
    bool doingSomething(int a, double b) {
        return complexMethod([this](auto i, auto d) {
            return myWay(i, d); }, a, b);
    }
    bool doingAnotherThing(int a, double b) {
        return complexMethod([this](auto i, auto d) {
            return otherWay(i, d); }, a, b);
    }
};

int main() {
    B b{};
    std::cout << std::boolalpha << b.doingSomething(3, 5.5) << "\n";
    std::cout << std::boolalpha << b.doingAnotherThing(3, 5.5) << "\n";
}

// Outputs:
//
//   true
//   false

Which technique is recommended? Why (speed, flexibility, readility...)?

Item 34 of Scott Meyer's Effective Modern C++ book is titled Prefer lambdas to std::bind. It ends with a summary saying: Lambdas are more readable, more expressive, and may be more efficient than using std::bind. However, it also mentions a case when std::bind may be useful over lambdas.