Reputation: 41
I've read several topics about that kind of problem - but can't find a simple and good solution. Here is the code:
void SomeFunction() { }
class A {
public:
typedef std::function<void(void)> AFunction;
static void AMethod(AFunction f) { f(); }
};
class B {
public:
void B1Method() { }
void BCorrectCall() { A::AMethod(SomeFunction); }
void BIncorrectCall() { A::AMethod(B1Method); }
};
Problem is here void BIncorrectCall() { A::AMethod(B1Method); }
, where I receive error about invalid casting. What is the simplest way to achieve that kind of behaviour? Thanks a lot for any advice!
Upvotes: 1
Views: 181
Reputation: 24738
The issue is that B::B1Method()
is a non-static
member function in B
and, therefore, it needs to be called on an instance of B
.
If the implementation of B1Method()
doesn't use any non-static
data member of B
and it doesn't call any other non-static
member function of B
, then simply declaring it as static
will work with your current implementation of BIncorrectCall()
as you will no longer need to call B1Method()
on an instance of B
:
class B {
public:
static void B1Method() { } // static now
void BCorrectCall() { A::AMethod(SomeFunction); }
void BIncorrectCall() { A::AMethod(B1Method); } // no change
};
Otherwise, you have to keep an object of type B
whenever you want to call B1::B1Method()
.
Upvotes: 2
Reputation: 1322
The problem is that 'B1Method' is not a simple function - it's a class method. That means that when you call myB.B1Method()
, you're actually calling 'B1Method(&myB)', effectively passing the this
pointer as a hidden argument - so you can't convert M1Method
to a std::function
without specifying which object it should act on.
One approach that should work is using std::bind to construct a callable object from a combination of an object (class instance) and the method. Something like:
void BNowCorrectCall() { A::AMethod(std::bind(&B::B1Method, this)); }
Upvotes: 0
Reputation: 38425
B1Method
is not void(*)(void)
, it's void(B1::*)(void)
.
You may do
void BIncorrectCall() { A::AMethod(std::bind(&B1::B1Method, this)); }
};
Upvotes: 2
Reputation: 96081
Use a lambda:
A::AMethod([this]{B1Method();});
It doesn't matter in this case, but if you wanted to store AFunction f
and use it after the call to AMethod
, you'd have to ensure that the B
instance (the address of which is saved in the lambda) says alive as long as you use the function.
C++17 allows you to capture *this
instead, which will copy the entire B
instance into lambda, but normally it's not what you want.
You could do something similar with std::bind
(see the other answer), but lambdas are more flexible.
Upvotes: 2
Reputation: 12909
The easiest way is to make it static
and so there is no this
object, but if you need it (the this
object), you can use lambdas
:
class B {
public:
void B1Method() { }
void BCorrectCall() { A::AMethod(SomeFunction); }
void BIncorrectCall() {
std::function<void(void)> el = [&](){this->B1Method();};
A::AMethod(el);
}
};
Upvotes: 0