2

I was wondering if its possible to initialize a substate machine by using a non-default constructor. I know one can do:

sub = sml::state<Sub>;

And use the sub I.e:

auto sub = sml::state<Sub>;
return make_transition_table(
     *"init"_s + event<Start>   / print(data_) = sub
     ,state<Sub> + event<End>  / print(data_) = X
 );

But if the Sub statemachine has a non-default constructor, is it possible to use that constructor to initiate the machine and then use that in the Composite machine?

Example:

struct Sub
{
    Sub(int){}
    auto operator()() const {
        using namespace sml;
        return make_transition_table(
            *"Entry"_s + event<ES1> = X
        );
    }

};

Here is an example: https://cpp.godbolt.org/z/zjvWsvscY

Complete example code:

namespace sml = boost::sml;

struct Context
{
    int x_{};
};

struct Data
{
    int y_{};
};


struct Start{};
struct End{};
struct ES1{};

auto print(Data data)
{
    return [data](Context& ctx) 
    {
        std::cout << "Context: " << ctx.x_ << " data: "<< data.y_ << '\n';
        ++ctx.x_;
    };
}

struct Sub
{
    //Sub(int){}
    auto operator()() const {
        using namespace sml;
        return make_transition_table(
            *"Entry"_s + event<ES1> = X
        );
    }

};



struct Composite
{
    Composite(Data data): data_{std::move(data)}{}
    auto operator()() const {
        using namespace sml;
        auto sub = sml::state<Sub>;
        return make_transition_table(
            *"init"_s + event<Start> / print(data_) = sub
            ,state<Sub> + event<End>  / print(data_) = X
        );
    }

    Data data_;
};


int main()
{
    //Sub sub{};

    Data data;
    Context ctx;
    sml::sm<Composite> sm(Composite{data}, ctx);
    sm.process_event(Start{});
    sm.process_event(ES1{});
    sm.process_event(End{});
    return 0;
}
sehe
  • 374,641
  • 47
  • 450
  • 633
Calle
  • 51
  • 3
  • I'm not convinced this is possible (unless you use the Boost DI integration, maybe?). See also my earlier encounter https://stackoverflow.com/a/66217733/85371 – sehe Mar 23 '22 at 13:16
  • 1
    Thanks! I'm starting to lean against that its not possible, and that sending a context through injection is the only way to get data to a substate. The link further reinforces my understanding that this is probably not possible. I guess one way to do it is to build Context that mirrors the statemachines hierarchi i.e ` struct Context { Composite { ........ struct Sub_1 { ...... }; }; ` – Calle Mar 23 '22 at 13:27

1 Answers1

0

Assuming you can initialize Sub at the same time you initialize Composite, you might be able to handle it the same exact way that you're already doing.

Here is an example: https://cpp.godbolt.org/z/YKxWzcPza

Add Sub{someint} to the sm constructor:

sml::sm<Composite> sm(Composite{data}, Sub{666}, ctx);

Corresponding sub state and action:

auto printSub(int z)
{
    return [z](Context& ctx) 
    {
        std::cout << "Context: " << ctx.x_ << " z: "<< z << '\n';
        ++ctx.x_;
    };
}

struct Sub
{
    Sub(int z): z_{z}{}
    auto operator()() const {
        using namespace sml;
        return make_transition_table(
            *"Entry"_s + event<ES1> / printSub(z_) = X
        );
    }
    int z_;
};
kielby
  • 31
  • 1