lemonade
lemonade

Reputation: 107

How can I pass a method of an object's class as std::function?

I have a function that needs to get std::function-type parameter. I also have an abstract-type pointer to an object. Is it possible to pass the method using only an object?

The function signature:

void foo(std::function<bool(int i)>);

The classes sample:

class IBase // interface
{
public:
    virtual bool sampleMethod(int i) = 0;
};

class Child1 : public IBase // one of the classes that inherit from IBase
{
public:
    bool sampleMethod(int i) override;
};

So there is this pointer to an object of one of the Child classes:

std::unique_ptr<IBase> ptr;

And I want to use it to pass the sampleMethod as a parameter of foo. Is there any way to do it using std or boost?

Upvotes: 7

Views: 6594

Answers (3)

mpen
mpen

Reputation: 283043

I started writing this based on Paul's answer:

_window.setCursorPosCallback(std::bind(&RenderWorld::mouseCallback, this, std::placeholders::_1,std::placeholders::_2));

But clang-tidy told me to change it to this instead:

_window.setCursorPosCallback([this](auto && x, auto && y) { 
    mouseCallback(std::forward<decltype(x)>(x), std::forward<decltype(y)>(y)); 
});

So that's kinda cool

Upvotes: 3

catnip
catnip

Reputation: 25388

You can do this with std::bind and a placeholder:

foo (std::bind (&IBase::sampleMethod, ptr.get (), std::placeholders::_1));

You can also use a lambda which captures ptr:

foo ([&ptr] (int i) { return ptr->sampleMethod (i); });

In either case, as Yakk - Adam Nevraumont says, make sure that ptr outlives any references made to it, or copies made of it, in foo.

Live demo

Upvotes: 6

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275740

This is C++, so you have to worry about lifetime. Your question completely ignores lifetime; that is a bad thing.

Whenever you talk about anything in C++ you must be clear about the lifetime of everything involved. One way to be clear about it is to talk about ownership. Another is to say one thing is to talk about scope.

The lifetime of:

void foo(std::function<bool(int i)> f);

f and copies of it is not clear. If f and all copies are not going to live past the exit of foo, that is completely different than if f or copies could live past the end of foo.

Part of this is not your fault; the C++ std library lacks a vocabulary type to describe "callable object with no state ownership" (a function_ref), so people use the value-semantics std::function instead.

Supposing what you really want is a function_ref<void(int)>, then you can just do this:

foo( [&](int i){ return ptr->sampleMethod(i); } );

and done; the scope guarantees (ptr outlives the call to foo, and f and its copies will not outlive foo) mean lifetime is accounted for.

If however that foo may keep a copy of f, you have two problems. First, ptr claims unique ownership over the lifetime of *ptr; but f also claims ownership over the object it wants to call.

What more, std::function can be copied; which means either the object it invokes must be copied, or we are forced to have shared ownership.

So after foo does *ptr need to available outside? Do copies of *ptr make sense, or shared ownership between the copies of f of *ptr? More ownership questions, and the answers to them change what the right solution to your problem is.

In a more perfect world, function, moveonly_function, function_ref would all exist, and your choice would inform what you need here and simplify the solition.

Upvotes: 2

Related Questions