0

So, I thought I had understood member function pointers and std::fuction, but sadly this is not the case yet.

I have the following code - its some early bits of a state machine, but I am struggling. let me paste the code:

#include <iostream>
#include <functional>
#include <map>

//forward decls
class state_t;

enum event_t
{
    ev_start = 0,
    ev_middle,
    ev_end
};

struct transition_t
{

    //std::function<bool()> guard_function();
    std::function<bool()> guard_function;
    state_t *p_next_state;
};

class state_t
{
public:
    std::map<event_t, transition_t> transitions;

    bool some_guard()
    {
        std::cout << "check the guard condition - all is well" << std::endl;
        return true;
    }
};

int main()
{
    std::cout << "Hello World!" << std::endl;

    state_t s1;
    state_t s2;

    // Setup transitions

    s1.transitions[event_t::ev_start]  = transition_t{s1::some_guard, &s2};
    s1.transitions[event_t::ev_middle] = transition_t{nullptr, &s2}; // no guard

    event_t test_event = event_t::ev_start;

    auto trans = s1.transitions.find(event_t::ev_start);
    if (trans != s1.transitions.end())
    {
        // change state - TBD
        std::cout << "changingn state" << std::endl;
    }

    return 0;
}

Ok, so:

  • event_t is just some enums
  • transition_t is meant to contain a pointer to some guard function that returns a bool and a pointer to the next state.
  • state_t has a map of events and transitions and contains some guard functions that can be stored in the transition_t.

So in main() I am trying to construct some states...

s1.transitions[event_t::ev_start]  = transition_t{s1::some_guard, &s2};   // <--- this line fails
s1.transitions[event_t::ev_middle] = transition_t{nullptr, &s2}; // <--- this line works (not so surprised)

But I can't quite figure out how to sort this. I have done this in the past with lambdas and templates... but I really wanted to give std::function a go to see if its better / easier...

Any pointers/guides what to do here would be welcome even if its using lambdas :), but I would prefer to get std::function working

code_fodder
  • 15,263
  • 17
  • 90
  • 167
  • 1
    Note that names ending in `_t` are reserved by POSIX, in which case your cose may not work on POSIX systems. – rubenvb Apr 12 '18 at 17:31
  • @rubenvb oh man.... but its so hard to find a good name :( ...`state` and `event` - but good point : ) – code_fodder Apr 12 '18 at 17:45
  • 1
    N.B. as well as providing an object to call the member function on (as explained in the duplicate) you also need to use the right syntax to form a pointer-to-member: `&state_t::some_guard` not `s1::some_guard` – Jonathan Wakely Apr 12 '18 at 17:45
  • 1
    just drop the prebuilt amd suffixes and if you meet Amy ambiguity just move them into a namespace ;) – rubenvb Apr 12 '18 at 17:46
  • @JonathanWakely - yeah, I had been trying loads of things - that was my last effort after I gave up and came here! thanks : ) .. ps sorry all for the dup – code_fodder Apr 12 '18 at 17:47
  • @rubenvb - namespace - great idea : )) ... well actually I'll move them into a class eventually : ) – code_fodder Apr 12 '18 at 17:48

1 Answers1

3

this should work as you need to bind the member function to it is instance.

thanks to @Barry comment below it looks much better to use the lambda solution over bind

s1.transitions[event_t::ev_start] = transition_t{ [&s1] { return s1.some_guard(); }, &s1 };
s1.transitions[event_t::ev_start] = transition_t{ std::bind(&state_t::some_guard, &s1), &s1 };

some performance thread i found of bind vs lambda. std::bind vs lambda performance

also lambda function looks more easy to read.

Arkady Godlin
  • 588
  • 2
  • 9
  • And it does sir! - bind is the key ingredient I had not used yet, thanks : ) – code_fodder Apr 12 '18 at 17:45
  • Prefer `[&s1]{ return s1.some_guard(); }` to `bind()`. It's strictly better in all important respects (it's even shorter than the `bind()` in this case!) – Barry Apr 12 '18 at 18:05