C++ invalid function type casting

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

Answers (5)

jfMR
jfMR

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

Arunas
Arunas

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

3CxEZiVlQ
3CxEZiVlQ

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

HolyBlackCat
HolyBlackCat

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

Alberto
Alberto

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

Related Questions