1

Is it possible, with C++ 11 or Boost, to create an object that stores an object pointer (instance), method pointer and some arguments and can invoke this method with these arguments later? I mean - how to do it using only std or Boost templates? I'm pretty sure it is possible, but don't know what's the best way.

And here's the real question: is it in any way possible to store several such objects that refer to different methods (with diferent signatures) in the same container?

Xeo
  • 129,499
  • 52
  • 291
  • 397
Violet Giraffe
  • 32,368
  • 48
  • 194
  • 335
  • `Is it possible, with C++ 11 or Boost, to create an object that ... ` Yes. `std::bind`, `boost::bind`. – Lightness Races in Orbit Aug 14 '13 at 20:43
  • `Is it in any way possible to store several such objects that refer to different methods (with diferent signatures) in the same container` No, not really. Why would you want to do that? – Lightness Races in Orbit Aug 14 '13 at 20:43
  • @LightnessRacesinOrbit: in my specific case it would allow for a very convenient inter-thread call mechanism. Create calls in worker thread, invoke in UI thread, and it doesn't have to care about signatures. – Violet Giraffe Aug 14 '13 at 20:47
  • 1
    Oh, well if you're pre-binding all the arguments, then that's fine. Because the resulting functor will have _zero_ arguments and a _void_ return type; doesn't matter that the _actual_ function being called has arguments, because you already bound them. Yes, this is a common approach. – Lightness Races in Orbit Aug 14 '13 at 20:50
  • @LightnessRacesinOrbit: great, that's the part I was missing! Thanks. – Violet Giraffe Aug 14 '13 at 20:51

2 Answers2

4

That's the classic use case for std::bind and std::function:

#include <functional>
#include <vector>

using namespace std::placeholders;   // for _1, _2, ...

std::vector<std::function<int(double, char)>> v;

Foo x;
Bar y;

v.emplace_back(std::bind(&Foo::f, &x, _1, _2));         // int Foo::f(double, char)
v.emplace_back(std::bind(&Bar::g, &y, _2, true, _1));   // int Bar::g(char, bool, double)
v.emplace_bacK(some_free_function);                     // int some_free_function(double, char)

To use:

for (auto & f : v) { sum += f(1.5, 'a'); }
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
3

Check out std::bind offered by C++11. It does exactly what you want. You don't even need boost for this. For example:

class C
{
public:
  void Foo(int i);
}

C c;

// Create a function object to represent c.Foo(5)
std::function<void(void)> callLater=std::bind(&C::Foo,std::ref(c),5);

// Then later when you want to call c.Foo(5), you do:
callLater();
Michael Goldshteyn
  • 71,784
  • 24
  • 131
  • 181
  • But can I store different function objects in the same container? – Violet Giraffe Aug 14 '13 at 20:42
  • 2
    @VioletGiraffe The resulting object can be easily stored in a [`std::function`](http://en.cppreference.com/w/cpp/utility/functional/function). If the function objects all have the same signature, you could make a container for them, e.g., `std::vector>`. – Casey Aug 14 '13 at 20:42
  • .. but not if they don't. – Lightness Races in Orbit Aug 14 '13 at 20:44
  • You cannot easily store function objects of different types in the same container. Also, you cannot compare function objects with each other, except to test if they are both empty or not. – Michael Goldshteyn Aug 14 '13 at 20:45
  • 1
    Ah yes the OP is binding _all_ the parameters, so the key here is that an expression `callLater()` really is all that's required (which has the corollary of homogeneous storage). +1 – Lightness Races in Orbit Aug 14 '13 at 20:51