1

What is the approach to have a vector to schedule method calls of a class. I would like to have a vector of methods, something like this:

class Model {
    using task_t = std::function<void()>;
    std::vector<std::vector<task_t>> _frameTasks;

    void add_function() { _frameTasks[3].push_back(&(this->function()); }
    void function() {std::cout << "hi"; }
    void step() {
         for (auto task : _frameTasks[3]) task();
    }
}

But the compiler complains that:

error: ISO C++ forbids taking the address of a bound member function to form a pointer to member function. 

How could I solve this issue or what is the right approach?

Blasco
  • 1,607
  • 16
  • 30
  • 1
    You need to use `std::bind`, see here: https://stackoverflow.com/questions/37636373/how-stdbind-works-with-member-functions – UnholySheep Feb 20 '18 at 12:49
  • 1
    A pointer to the function is written `&Model::function`. (But its type is `void(Model::*)()`) – molbdnilo Feb 20 '18 at 12:49
  • 1
    Use `void add_function() { _frameTasks[3].push_back(std::bind(&Model::function, this)); }` – jdehesa Feb 20 '18 at 12:52
  • 4
    Or forget all about `std::bind` and use `push_back( [this](){ function(); } )`. And usually prefer `for ( auto&& var : range )` to `for ( auto var : range )`. – aschepler Feb 20 '18 at 12:53
  • @aschepler Oh, that's such a nice solution, thank you! – Blasco Feb 20 '18 at 12:54
  • @aschepler would it this case the auto&& matter? I wouldn't like to use it without knowing why – Blasco Feb 20 '18 at 13:02
  • @WooWapDaBug `auto var` always makes a copy of the element, which is usually unnecessary. `auto&& var` gives you a reference to the element. (`auto& var` would usually work just as well, but not if the iterator's `operator*` returns a proxy, like for `std::vector`.) Here a `std::function` copy might need to do a virtual clone or manipulate a shared use-count or something, but we might as well just skip all that. (`auto var : range` can be appropriate if for some reason you want to modify a copy of the range element without modifying the original element.) – aschepler Feb 20 '18 at 13:14

1 Answers1

2

&(this->function()) is applying & to the result of the call to the function() member function. The default operator& requires an lvalue, however, the expression this->function() is not an lvalue.

Writing &Model::function won't work either because it is a pointer to a member function (as opposed to a pointer to a function). Its type is void (Model::*)(), i.e.: a pointer to a Model's (non-static) member function that takes no parameters and returns nothing.

You need some way to specify the Model object on which the function() member function will be called.

Since C++11 you can achieve that by simply using a lambda expression:

void add_function() {
    _frameTasks[3].push_back(
        [this](){ add_function(); }
    );
}
JFMR
  • 23,265
  • 4
  • 52
  • 76
  • `&(this->function())` is not a pointer to member function. It immediately calls the function and attempts to take the address of the returned value (which is not valid if the return type is `void`). `&Model::function` is the only syntax for a pointer to member function. – aschepler Feb 20 '18 at 13:17
  • Thanks, it was completely wrong. Either way, I think `&` requires an lvalue, doesn't it? So it can't work even if it is non-`void`. – JFMR Feb 20 '18 at 13:22
  • Not necessarily. https://wandbox.org/permlink/AFiry9AQUL5AMF7X – Baum mit Augen Feb 20 '18 at 13:39
  • @BaummitAugen Good point. The question would be now: can the `operator&` for `Model` be overloaded outside `Model`'s definition ? If so, OP may as well consider `std::addressof()` instead of `operator&`. – JFMR Feb 20 '18 at 13:46
  • It sure can. https://wandbox.org/permlink/Q4u9vvLAsH2K9et4 Not for the actual function type though, of course. – Baum mit Augen Feb 20 '18 at 13:49
  • @BaummitAugen Really interesting. Anyway it should be overloaded for `Model::function()`'s return type, not for `Model` itself. – JFMR Feb 20 '18 at 13:50
  • Yeah, the whole thing about overloaded `operator &` is rather tangential to the discussion at hand to begin with. – Baum mit Augen Feb 20 '18 at 13:50