2

I want to retrieve state from a function object. But the function object has been casted to a function<> template. How can I do it?

I mean:

function object:

class Counter {
private:
    int counter_;
public:
    Counter():counter_(0) {cout << "Constructor() called" << endl;}
    Counter(int a):counter_(a) {cout << "Constructor(a) called" << endl;}

    void operator()(int sum) {
        cout << counter_++ + sum << endl;
    }

int getCounter() { return counter_;}
};

In main. My first step is use object directly:

int main() {
    Counter a(10);
    a(0);
    a(0);

    cout << "Counter: " << a.getCounter() << endl;

Its shows:

Constructor(a) called

10

11

Counter: 12

It's ok and it's what I expected.

But in

Counter b(10);
function<void(int)> f = b;
f(0);
f(0);
cout << "Counter: " << b.getCounter() << endl;

It shows

Constructor(a) called

10

11

Counter: 10

Argh!, I supposed that f was a wrapper of real object so modifying f we really modify b. No: f has a copy of b, but I can't call to f.getCounter() so How can I get State (counter_ var) from f?

I can't use directly Counter class (in this example) because I have some other similar classes with same signature "void(int)" And I want to use them in indistinctly in a caller function.

I can avoid std::function template at all using a common base class for all my function object but I think there is a solution more C++11 with STL and templates...

So, Is there that solution?

Thanks

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
jamarier
  • 23
  • 2

2 Answers2

3

Create the function from a reference wrapper:

function<void(int)> f = std::ref(b);

giving the result:

Constructor(a) called
10
11
Counter: 12

Of course, you need to make sure that the function isn't invoked after the counter is destroyed.

If you need to access the counter from the function object, then use its target member:

if (Counter * c = f.target<Counter>()) {
    std::cout << "Counter: " << c->getCounter() << '\n';
} else {
    std::cout << "Not a counter.\n";
}
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
2

This is not a cast:

function<void(int)> f = b;

A std::function is been constructed, with a copy of your function object as its target.

You can either make the target a reference to your function object:

function<void(int)> f = std::ref(b);

Or let f contain a copy but then retrieve that copy from f:

Counter* c = f.target<Counter>();
cout << "Counter: " << c->getCounter() << endl;

It's usually safer to let f contain a copy as you don't ned to worry about the lifetime of b.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521