Xavier Arias Botargues
Xavier Arias Botargues

Reputation: 357

std::function parameter subclass

I've trying to avoid C-style function pointers in favor of std::function objects, but I'm having problems calling member functions while inheriting.

I have a method that receives a std::function:

class A
{
public:
    void testCallbackA();

    // this is unrelated, but I need some features from the superclass
    void goingToNeedThisWhenCallingTestCallbackA(int someParams); 
};

void method(std::function<void(A*)> callback);

method(&A::testCallbackA); // this works fine 

All good by now, But when I want to use A subclasses with method I need to cast the function pointer:

class B : public A
{
public:
    void testCallbackB() { }
};

method(&B::testCallbackB); // this fails

std::function<void(A*)> call = &B::testCallbackB; // this fails
std::function<void(B*)> call = &B::testCallbackB; // this works

If I want to be able to call method(&B::testCallbackB) I need to typedef a function pointer and cast it this way:

typedef void (A::*Callback)();

std::function<void(A*)> call = (Callback)&B::testCallbackB; // this works

Can I avoid this typedef? Can I avoid the cast? I've tried looking into std::bind with no luck.

Any ideas?

Upvotes: 0

Views: 553

Answers (3)

user2545918
user2545918

Reputation:

If I understand your problem well, then I suggest you to make testCallbackA in class A virtual, and then simply use &A::testCallbackA when calling method.

Dynamic method dispatch will take care of calling the method of the actual class, and you do not have to circumvent type safety by hand.

Upvotes: 1

Casey
Casey

Reputation: 42564

This conversion should fail, because it's a bad idea. std::function<void(A*)> is callable with any A*, regardless of whether or not the actual object pointed to is a B. The result of calling a B member function on an A that is not a B is undefined behavior.

Upvotes: 5

Some programmer dude
Some programmer dude

Reputation: 409356

You might need std::bind, like in

B b;
method(std::bind(&B::testCallbackB, b));

Upvotes: 4

Related Questions