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 callB:myWay()
andB::otherWay()
but using lambdas. I don't want to substituteB:myWay()
andB::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.