Giter Site home page Giter Site logo

boost-ext / sml Goto Github PK

View Code? Open in Web Editor NEW
1.1K 74.0 167.0 32.66 MB

C++14 State Machine library

Home Page: https://boost-ext.github.io/sml

License: Boost Software License 1.0

C++ 94.52% Makefile 1.54% CMake 2.73% Shell 0.07% Python 1.01% Gnuplot 0.13%
sml metaprogramming design-patterns state-machine

sml's Introduction

Boost Licence Version Linux Codecov Try it online


SML (State Machine Language)

Your scalable C++14 one header only State Machine Library with no dependencies

Rise of the State Machines

https://www.youtube.com/watch?v=Zb6xcd2as6o



Let's release a TCP connection!

tcp release

Quick start

Download

[Boost::ext].SML requires only one file. Get the latest header here!

Include

#include <boost/sml.hpp>
namespace sml = boost::sml;

Dependencies

struct sender {
  template<class TMsg>
  constexpr void send(const TMsg& msg) { std::printf("send: %d\n", msg.id); }
};

Events

struct ack { bool valid{}; };
struct fin { int id{}; bool valid{}; };
struct release {};
struct timeout {};

Guards

constexpr auto is_valid = [](const auto& event) { return event.valid; };

Actions

constexpr auto send_fin = [](sender& s) { s.send(fin{0}); };
constexpr auto send_ack = [](const auto& event, sender& s) { s.send(event); };

State Machine

struct tcp_release {
  auto operator()() const {
    using namespace sml;
    /**
     * Initial state: *initial_state
     * Transition DSL: src_state + event [ guard ] / action = dst_state
     */
    return make_transition_table(
      *"established"_s + event<release>          / send_fin  = "fin wait 1"_s,
       "fin wait 1"_s  + event<ack> [ is_valid ]             = "fin wait 2"_s,
       "fin wait 2"_s  + event<fin> [ is_valid ] / send_ack  = "timed wait"_s,
       "timed wait"_s  + event<timeout>                      = X
    );
  }
};

Usage

int main() {
  using namespace sml;

  sender s{};
  sm<tcp_release> sm{s}; // pass dependencies via ctor
  assert(sm.is("established"_s));

  sm.process_event(release{}); // complexity O(1)
  assert(sm.is("fin wait 1"_s));

  sm.process_event(ack{true}); // prints 'send: 0'
  assert(sm.is("fin wait 2"_s));

  sm.process_event(fin{42, true}); // prints 'send: 42'
  assert(sm.is("timed wait"_s));

  sm.process_event(timeout{});
  assert(sm.is(X));  // terminated
}

MSVC-2015 (Example)

  • use state<class state_name> instead of "state_name"_s
  • expliclty state a lambda's result type auto action = [] -> void {}

Compile

  • GCC/Clang
    $CXX -std=c++14 -O2 -fno-exceptions -Wall -Wextra -Werror -pedantic tcp_release.cpp
  • MSVC
    cl /std:c++14 /Ox /W3 tcp_release.cpp

tcp_release.cpp Clang-3.8 GCC-6.3 MSVC-2015
Compilation Time 0.102s 0.118s 0.296s
Binary size (stripped) 6.2kb 6.2kb 105kb
ASM x86-64 -
https://godbolt.org/z/y99L50

main: # @main
  pushq %rax
  movl $.L.str, %edi
  xorl %esi, %esi
  xorl %eax, %eax
  callq printf
  movl $.L.str, %edi
  movl $42, %esi
  xorl %eax, %eax
  callq printf
  xorl %eax, %eax
  popq %rcx
  retq
.L.str:
  .asciz "send: %d\n"
      

Run

Output (https://wandbox.org/permlink/WbvV9HsIyiPkCFw7)

send: 0
send: 42

Benchmark

Complex Test

Enum/Switch Variant [Boost::ext].SML - 1.1.0 Boost-1.65.MSM-eUML Boost-1.65.Statechart
Compilation time 0.132s 15.321s 0.582s 1m15.935s 5.671s
Execution time 679ms 827ms 622ms 664ms 2282ms
Memory usage 1b 2b/8b 1b 120b 224b
Executable size 15K 187K 34K 611K 211K

Examples

Arduino UML

Arduino Code

https://godbolt.org/z/Y983h4

Arduino Board

https://www.tinkercad.com/things/9epUrFrzKP3


AVR performance

https://godbolt.org/z/qhx8Md


match3

match3

https://github.com/modern-cpp-examples/match3


Documentation


Disclaimer [Boost::ext].SML is not an official Boost library.

sml's People

Contributors

anthonyvh avatar aunsbjerg avatar bagira80 avatar benjaminw3 avatar christophpurrer avatar devzeb avatar drorspei avatar feltech avatar guicodron avatar guiserle avatar j-meyers avatar joeloser avatar joyifbam5 avatar justwillim avatar kamibo avatar kiwixz avatar kris-jusiak avatar krzysztof-jusiak avatar mriemensberger avatar ooxi avatar palarson avatar pooouf avatar ramirisu avatar redboltz avatar rhaschke avatar rijom avatar romainreignier avatar rvdvvdw avatar sdebionne avatar uyha avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sml's Issues

Add support for exception handling

The code in guards and transitions can throw exceptions that should be transformed in events by the state machine engine. These exception events must be managed just after the exception is caught.

An exception throw in a guard should left the sm in the current state.

An exception throw in an action should left the sm in the nesting state of the source state for external and local transitions and the current state for internal transitions.

[feature] exceptions handling

pseudo states:
src_st + event [guard] / action = dst_st|catch_st

transitions:

src + event [guard]/action = dst // guard throws runtime_error
src + exception<runtime_error> = X // handle exception

msm-lite is not thread safe

Documentation states that msm-lite is thread-safe where it is not. When two threads send events to the same FSM, actions are executed in parallel, and current state of FSM is overwritten. Please update documentation to state this.

If you plan to update code to make it thread-safe, please allows to create both thread-safe and thread-unsafe FSMs - synchronization is an overhead which is not always needed or wanted.

All states of orthogonal regions are reentered when transition is triggered in any region

#include <cstdio>
#include <boost/msm-lite.hpp>

namespace msm = boost::msm::lite;

struct e1 {};
struct e2 {};
struct e3 {};
struct e4 {};

struct A {
  auto configure() const noexcept {
    using namespace msm;
    using msm::on_exit;
    state<class A1> a1;
    state<class A2> a2;
    return make_transition_table(
        *a1 + event<e4> = a2,
        a1 + on_entry / [] { printf("Entering A1\n"); },
        a1 + on_exit / [] { printf("Leaving A1\n"); },
        a2 + on_entry / [] { printf("Entering A2\n"); },
        a2 + on_exit / [] { printf("Leaving A2\n"); }
    );
  }
};

struct B {
  auto configure() const noexcept {
    using namespace msm;
    using msm::on_exit;
    state<class B1> b1;
    state<class B2> b2;
    return make_transition_table(
        *b1 + event<e4> = b2,
        b1 + on_entry / [] { printf("Entering B1\n"); },
        b1 + on_exit / [] { printf("Leaving B1\n"); },
        b2 + on_entry / [] { printf("Entering B2\n"); },
        b2 + on_exit / [] { printf("Leaving B2\n"); }
    );
  }
};

struct C {
  auto configure() const noexcept {
    using namespace msm;
    using msm::on_exit;
    state<class C1> c1;
    state<class C2> c2;
    return make_transition_table(
        *c1 + event<e4> = c2,
        c1 + on_entry / [] { printf("Entering C1\n"); },
        c1 + on_exit / [] { printf("Leaving C1\n"); },
        c2 + on_entry / [] { printf("Entering C2\n"); },
        c2 + on_exit / [] { printf("Leaving C2\n"); }
    );
  }
};

struct TopState {
  auto configure() const noexcept {
    using namespace msm;
    using msm::on_exit;
    state<sm<A>> a;
    state<class X> x;
    state<sm<B>> b;
    state<class Y> y;
    state<sm<C>> c;
    state<class Y> z;
    return make_transition_table(
        *"init1"_s = a,
        a + event<e1> = x,
        *"init2"_s = b,
        b + event<e2> = y,
        *"init3"_s = c,
        c + event<e3> = z,
        a + on_entry / [] { printf("Entering A\n"); },
        a + on_exit / [] { printf("Leaving A\n"); },
        x + on_entry / [] { printf("Entering X\n"); },
        x + on_exit / [] { printf("Leaving X\n"); },
        b + on_entry / [] { printf("Entering B\n"); },
        b + on_exit / [] { printf("Leaving B\n"); },
        y + on_entry / [] { printf("Entering Y\n"); },
        y + on_exit / [] { printf("Leaving Y\n"); },
        c + on_entry / [] { printf("Entering C\n"); },
        c + on_exit / [] { printf("Leaving C\n"); },
        z + on_entry / [] { printf("Entering Z\n"); },
        z + on_exit / [] { printf("Leaving Z\n"); }
    );
  }
};

int main(int argc, char** argv) {
  using namespace msm;
  sm<TopState> m;
  printf("\nProcessing E2\n");
  m.process_event(e2{});
  return 0;
}

Processing e2 should trigger transition b -> y while leaving other regions in states a and c. Code prints:

...
Processing E2
Leaving A1
Leaving A
Leaving B1
Leaving B
Leaving C1
Leaving C
Entering A1
Entering A
Entering Y
Entering C1
Entering C

In response to the event, all three top substates are exited only to be re-entered again in parallel with triggered transition.

Add state machine inheritance

While is is not clear that UML supports state machine inheritance, a state machine is associated to a class that support inheritance.

The kind of things that state machine inheritance should support is

  • able to refine(decompose) a specific state.
  • able to refine a transition guard and/or action.
  • when the target state has been refined, able to change the target state of a transition by an associated entry point.

Entry/exit actions on composite states?

Is there a way to assign entry/exit actions to composite states? Maybe I'm not looking hard enough, but the following code can't be compiled:

#include <boost/msm-lite.hpp>

namespace msm = boost::msm::lite;

using msm::state;
using msm::event;
using msm::sm;
using msm::make_transition_table;

struct e1 {};
struct e2 {};
struct e3 {};
struct e4 {};

state<class LeafState1_1> ls1_1;
state<class LeafState1_2> ls1_2;

struct SubState1 {
  SubState1() {}
  auto configure() const noexcept {
    return make_transition_table(
        *ls1_1 + event<e1> = ls1_2,
        ls1_2 + event<e2> = ls1_1
    );
  }
};

state<class LeafState2_1> ls2_1;
state<class LeafState2_2> ls2_2;

struct SubState2 {
  SubState2() {}
  auto configure() const noexcept {
    return make_transition_table(
        *ls2_1 + event<e1> = ls2_2,
        ls2_2 + event<e2> = ls2_1
    );
  }
};

state<sm<SubState1>> ss1;
state<sm<SubState2>> ss2;

struct TopState {
  TopState() {}
  auto configure() const noexcept {
    using namespace msm;
    return make_transition_table(
        *ss1 + event<e3> = ss2,
        ss2 + event<e4> = ss1,
        ss1 + on_entry / [] { /* ... */ }  // Compilation error.
    );
  }
};

int main(int argc, char** argv) {
  SubState1 ss1_;
  sm<SubState1> ssm1_{ss1_};
  SubState2 ss2_;
  sm<SubState2> ssm2_{ss2_};
  TopState ts_;
  sm<TopState> m{ts_, ssm1_, ssm2_};

  m.process_event(e1{});
  m.process_event(e2{});

  m.process_event(e3{});

  m.process_event(e1{});
  m.process_event(e2{});

  m.process_event(e4{});
  return 0;
}

Is it implemented? As I understand it, transition between composite states should start with exit action of current leaf state, traverse upwards to enclosing state of transition while successively calling exit actions of composite states as they're being left, and then, similar way, successive call entry actions of state hierarchy it enters down to the final destination leaf/leaves. (In addition, I think leaf state's on_entry/on_exit aren't called when transitioning to/from composite state, but that's separate concern.)

P.S.: I'd gladly assign the label 'question' to the issue, but it appears I can't assign labels.

FSM as a private class member, uses methods as actions and guards

Could you add support for using class methods as actions and guards? I would like to do something like in example below. Please also add new example for this in documentation.
BTW, If something like this is possible now with lambdas, please add example for this too.

#include <msm-lite.hpp>
#include <iostream>
namespace msm = boost::msm::lite;

class Test
{
    struct Event1
    {
        int val;
    };

    struct TestFsmConfig
    {
        auto configure() const noexcept
        {
            using namespace msm;
            return make_transition_table(
                *"s1"_s + event<Event1> / &Test::handleEvent1 = "s2"_s,
                *"s2"_s + event<Event1> [&Test::guard1] / &Test::handleEvent1 = X
            );
        }
    };

    msm::sm<TestFsmConfig> testFsm;

    bool guard1(Event1& ev)
    { return ev.val > 0; }

    void handleEvent1(Event1& ev)
    { std::cout << "Got event 1, val = " << ev.val << std::endl; }

public:
    Test() : testFsm(this) {}

    void sendEvent1(int val)
    {
        testFsm.process_event(Event1{val});
    }
};

[question] refer to all known states

Hello, I just picked up msm-lite and I'm really looking forward to integrating it into my project, but I couldn't figure out if this feature that I want exists based on the documentation and examples.

I want to specify a transition that can occur from any states in a state machine, results from the same event, has the same side effects, and transitions to the same final state. Is there special syntax in msm-lite for this, to avoid copying the same logic for each transition?

For example, if the "final" state occurs when the "terminate" event occurs from state s1, s2, or s3, this is what I'd like to do... Even better would be a way to refer to all states without listing them all.

make_transition_table(
  s1 + e1 / [](){ } = s2,
  /* ... other transitions ... */ ,
  s1 | s2 | s3 + terminate / [](){ /* cleanup for terminate */} = final
);

Compilation error when configuration struct is nested inside class

When struct with transition table definition is nested as private member of class (see code below), compilation fails with following error. When the same struct is outside of class, code compiles successfully. I used gcc 5.3.0 from Cygwin x86-64. Please fix this.

test-err.cc:32:27: error: no type named ‘type’ in ‘struct boost::msm::lite::v_1_0_1::aux::enable_if<false, int>’
     msm::sm<FsmTestConfig2> myFsm2;
                           ^
test-err.cc:32:27: note: invalid template non-type parameter
#include <msm-lite.hpp>

namespace msm = boost::msm::lite;

struct e1 {};

struct FsmTestConfig1
{
    auto configure() const noexcept
    {
        using namespace msm;
        return make_transition_table(
            *"s1"_s + event<e1> / [](){} = X
        );
    }
};

class FsmTest
{
    struct FsmTestConfig2
    {
        auto configure() const noexcept
        {
            using namespace msm;
            return make_transition_table(
                *"s1"_s + event<e1> / [](){} = X
            );
        }
    };

    msm::sm<FsmTestConfig1> myFsm1; // OK
    msm::sm<FsmTestConfig2> myFsm2; // Compilation error

public:
    FsmTest(){}
};

int main()
{
    FsmTest fsmTest;
    return 0;
}

Anonymous explicit transitions from a substate don't seem to work

I can't seem to make things work with an anonymous explicit transition from a substate:

#include <boost/msm-lite.hpp>

namespace msm = boost::msm::lite;
using msm::state;
using msm::sm;

struct SubState {
  auto configure() const noexcept {
    using namespace msm;
    return make_transition_table(
        *"ss1"_s + "e2"_t = "final"_s
    );
  }
};

state<sm<SubState>> ss;

struct TopState {
  auto configure() const noexcept {
    using namespace msm;
    return make_transition_table(
        *"s1"_s + "e1"_t = ss,
        // ss("final"_s) + "e3"_t = "s2"_s   // Works.
        // ss("final"_s) / []{} = "s2"_s     // Compiles, but doesn't work.
        // ss("final"_s) = "s2"_s            // Compilation error.
    );
  }
};

int main(int argc, char** argv) {
  using namespace msm;
  sm<TopState> m;
  m.process_event("e1"_t);
  m.process_event("e2"_t);
  m.process_event("e3"_t);
  return 0;
}

Usual transition from a substate works fine. Anonymous transition causes compilation error. Transition with empty action does compile, but it's still not triggered when source state of the substate is entered. I wonder if it's supposed to work, or there's different notation?

It's probably low-priority, but such transitions are useful to make "exit point" pseudostates and keep transition logic (and possibly multiple transitions routed to exit) incapsulated inside substate.

Marking initial state in transition that originates from its nested state

How does one indicate initial state in an explicit transition that originates from the state nested inside the initial one, like in following example:

struct TopState {
  TopState() {}
  auto configure() const noexcept {
    using namespace msm;
    return make_transition_table(
        // Mark ss1 as initial state.
        *ss1(ls1_1) + event<e3> = ss2,  // Compilation error.
        ss2 + event<e4> = ss1
        /* ... */
    );
  }
};

Introducing separate initial state with anonymous transition to ss1 solves it, but is there a better way?

Entry (exit) actions aren't called on substates of a composite state that has no entry (exit) actions of its own

It appears that, if an enclosing composite state does not have entry or exit actions of its own (on any arbitrary state, even if it's not actually visited), then inside its substates' entry and exit actions aren't called either.

#include <cstdio>
#include <boost/msm-lite.hpp>

namespace msm = boost::msm::lite;

using msm::state;
using msm::event;
using msm::sm;
using msm::make_transition_table;

struct e1 {};
struct e2 {};
struct e3 {};

struct A {
  auto configure() const noexcept {
    using namespace msm;
    using msm::on_exit;
    state<class A1> a1;
    state<class A2> a2;
    return make_transition_table(
        *a1 + event<e2> = a2,
        a1 + on_entry / [] { printf("Entering A1\n"); },
        a1 + on_exit / [] { printf("Leaving A1\n"); }
    );
  }
};

struct B {
  auto configure() const noexcept {
    using namespace msm;
    using msm::on_exit;
    state<class B1> b1;
    state<class B2> b2;
    return make_transition_table(
        *b1 + event<e2> = b2,
        b1 + on_entry / [] { printf("Entering B1\n"); },
        b1 + on_exit / [] { printf("Leaving B1\n"); }
    );
  }
};

state<sm<A>> a;
state<sm<B>> b;
state<class C> c;

struct SM {
  auto configure() const noexcept {
    using namespace msm;
    using msm::on_exit;
    state<class Init> init;
    return make_transition_table(
        *init = a,
        a + event<e1> = b,
        b + event<e3> = c
        //, c + on_entry / [] {}   // (1)
        //, c + on_exit / [] {}    // (2)
    );
  }
};

int main(int argc, char** argv) {
  sm<SM> m;
  printf("Processing E1\n");
  m.process_event(e1{});
  return 0;
}

yields following output:

Processing E1

E.g. entry/exit actions on a(a1) and b(b1) during a -> b transition are not called. Uncommenting (1) yields:

Entering A1
Processing E1
Entering B1

Introducing dummy entry action on c enabled entry actions on a1 and b1. Uncommenting (2) gives

Processing E1
Leaving A1

And uncommenting both enables all actions:

Entering A1
Processing E1
Leaving A1
Entering B1

Entry actions are not called during state machine initialization

I've mentioned it in another issue, but only now tested it separately and making an issue of its own. When state machine is created and its initial state configuration is entered, no entry actions are called. Example:

#include <cstdio>
#include <cassert>
#include <boost/msm-lite.hpp>

namespace msm = boost::msm::lite;

using msm::state;
using msm::event;
using msm::sm;
using msm::make_transition_table;

struct e1 {};
struct e2 {};

state<class SubSubState1_1> ss1_1;
state<class SubSubState1_2> ss1_2;

struct SubState1 {
  SubState1() {}
  auto configure() const noexcept {
    using namespace msm;
    return make_transition_table(
        *ss1_1 + event<e1> = ss1_2,
        ss1_1 + msm::on_entry / [] { printf("Entering SS1_1.\n"); },
        ss1_2 + msm::on_entry / [] { printf("Entering SS1_2.\n"); },
        ss1_1 + msm::on_exit / [] { printf("Leaving SS1_1.\n"); },
        ss1_2 + msm::on_exit / [] { printf("Leaving SS1_2.\n"); }
    );
  }
};

state<class SubSubState2_1> ss2_1;
state<class SubSubState2_2> ss2_2;

struct SubState2 {
  SubState2() {}
  auto configure() const noexcept {
    using namespace msm;
    return make_transition_table(
        *ss2_1 + event<e1> = ss2_1,
        ss2_1 + msm::on_entry / [] { printf("Entering SS2_1.\n"); },
        ss2_2 + msm::on_entry / [] { printf("Entering SS2_2.\n"); },
        ss2_1 + msm::on_exit / [] { printf("Leaving SS2_1.\n"); },
        ss2_2 + msm::on_exit / [] { printf("Leaving SS2_2.\n"); }
    );
  }
};

state<sm<SubState1>> ss1;
state<sm<SubState2>> ss2;

struct TopState {
  TopState() {}
  auto configure() const noexcept {
    using namespace msm;
    return make_transition_table(
        *ss1 + event<e2> = ss2,
        ss1 + msm::on_entry / [] { printf("Entering SS1.\n"); },
        ss2 + msm::on_entry / [] { printf("Entering SS2.\n"); },
        ss1 + msm::on_exit / [] { printf("Leaving SS1.\n"); },
        ss2 + msm::on_exit / [] { printf("Leaving SS2.\n"); }
    );
  }
};

int main(int argc, char** argv) {
  SubState1 ss1_;
  sm<SubState1> ssm1_(ss1_);
  SubState2 ss2_;
  sm<SubState2> ssm2_(ss2_);
  TopState s_;
  sm<TopState> m(s_, ssm1_, ssm2_);
  assert(m.is(ss1));
  assert(ssm1_.is(ss1_1));
  return 0;
}

When ran, program shows nothing - asserts confirm that state machine entered desired configuration (ss1(ss1_1)), but entry actions were not called. Since entry actions set identity for states, machine will have not been initialized properly.

Introducing a dummy initial state and anonymous transition helps:

struct TopState {
  TopState() {}
  auto configure() const noexcept {
    using namespace msm;
    return make_transition_table(
        *"init"_s = ss1,
        ss1 + event<e2> = ss2,
        ss1 + msm::on_entry / [] { printf("Entering SS1.\n"); },
        ss2 + msm::on_entry / [] { printf("Entering SS2.\n"); },
        ss1 + msm::on_exit / [] { printf("Leaving SS1.\n"); },
        ss2 + msm::on_exit / [] { printf("Leaving SS2.\n"); }
    );
  }
};

Output:

Entering SS1_1.
Entering SS1.

I think action order is still incorrect (see #43), but states are initialized at least. It's not intuitive and error prone though, takes running into the bug to resort to the dummy state.

Initial states of composite regions can be entered/exited multiple times during initialization

#include <cstdio>
#include <boost/msm-lite.hpp>

namespace msm = boost::msm::lite;

struct TopState {
  auto configure() const noexcept {
    using namespace msm;
    using msm::on_exit;
    state<class A> a;
    state<class B> b;
    state<class C> c;
    return make_transition_table(
        *"init1"_s = a,
        *"init2"_s = b,
        *"init3"_s = c,
        a + on_entry / [] { printf("Entering A\n"); },
        a + on_exit / [] { printf("Leaving A\n"); },
        b + on_entry / [] { printf("Entering B\n"); },
        b + on_exit / [] { printf("Leaving B\n"); },
        c + on_entry / [] { printf("Entering C\n"); },
        c + on_exit / [] { printf("Leaving C\n"); }
    );
  }
};

int main(int argc, char** argv) {
  using namespace msm;
  sm<TopState> m;
  return 0;
}

The code above prints:

Entering A
Leaving A
Entering A
Entering B
Leaving A
Leaving B
Entering A
Entering B
Entering C

States A and B are entered, then re-entered again during initialization; I think they only should be entered once.

Doesn't compile with gcc-6

When trying to compile this example I get the following error:
g++-6 -std=c++14 hello_world.cpp -o hello_world

In file included from hello_world.cpp:8:0:
boost/msm-lite.hpp: In static member function ‘static bool boost::msm::lite::v_1_0_0::detail::transition_sub_impl<TSM, T, Ts ...>::execute(SM&, const TEvent&, boost::msm::lite::v_1_0_0::aux::byte&)’:
boost/msm-lite.hpp:968:126: error: parameter packs not expanded with ‘...’:
: transition_impl<T, Ts...>::execute(self, event, current_state);
^
boost/msm-lite.hpp:968:126: note: ‘decltype(auto)’
boost/msm-lite.hpp: In static member function ‘static bool boost::msm::lite::v_1_0_0::detail::transition_sub_impl::execute(SM&, const TEvent&, boost::msm::lite::v_1_0_0::aux::byte&)’:
boost/msm-lite.hpp:975:61: error: parameter packs not expanded with ‘...’:
return aux::try_get(self.deps_).process_event(event);
^
boost/msm-lite.hpp:975:61: note: ‘decltype(auto)’
boost/msm-lite.hpp: In constructor ‘boost::msm::lite::v_1_0_0::detail::sm< >::sm(TDeps&& ...)’:
boost/msm-lite.hpp:1152:107: error: parameter packs not expanded with ‘...’:
transitions_(aux::try_get(deps_).configure()) {
^
boost/msm-lite.hpp:1152:107: note: ‘decltype(auto)’
boost/msm-lite.hpp: In constructor ‘boost::msm::lite::v_1_0_0::detail::sm< >::sm(boost::msm::lite::v_1_0_0::detail::sm< >::deps_t&&)’:
boost/msm-lite.hpp:1156:117: error: parameter packs not expanded with ‘...’:
explicit sm(deps_t &&deps) BOOST_MSM_LITE_NOEXCEPT : deps_(deps), transitions_(aux::try_get(deps_).configure()) {
^
boost/msm-lite.hpp:1156:117: note: ‘decltype(auto)’
boost/msm-lite.hpp: In member function ‘void boost::msm::lite::v_1_0_0::detail::sm< >::update_composite_states(const boost::msm::lite::v_1_0_0::aux::type_list<TStates ...>&, ...)’:
boost/msm-lite.hpp:1317:37: error: parameter packs not expanded with ‘...’:
auto &sm = aux::try_get(deps_);
^
boost/msm-lite.hpp:1317:37: note: ‘decltype(auto)’
boost/msm-lite.hpp: In member function ‘void boost::msm::lite::v_1_0_0::detail::sm< >::update_composite_states(const boost::msm::lite::v_1_0_0::aux::type_list<>&, const true_type&, const boost::msm::lite::v_1_0_0::aux::type_list<TStates ...>&)’:
boost/msm-lite.hpp:1326:37: error: parameter packs not expanded with ‘...’:
auto &sm = aux::try_get(deps_);
^
boost/msm-lite.hpp:1326:37: note: ‘decltype(auto)’
boost/msm-lite.hpp: In member function ‘void boost::msm::lite::v_1_0_0::detail::sm< >::update_composite_states(const boost::msm::lite::v_1_0_0::aux::type_list<>&, const false_type&, ...)’:
boost/msm-lite.hpp:1335:70: error: parameter packs not expanded with ‘...’:
aux::try_get(deps_).initialize(typename T::initial_states_t{});
^
boost/msm-lite.hpp:1335:70: note: ‘decltype(auto)’
In file included from hello_world.cpp:8:0:
boost/msm-lite.hpp: In instantiation of ‘boost::msm::lite::v_1_0_0::aux::pool::pool(boost::msm::lite::v_1_0_0::aux::init&&, boost::msm::lite::v_1_0_0::aux::pool<TArgs ...>&&) [with TArgs = {}; Ts = {hello_world}]’:
boost/msm-lite.hpp:1152:107: required from ‘boost::msm::lite::v_1_0_0::detail::sm< >::sm(TDeps&& ...) [with TDeps = {}; typename boost::msm::lite::v_1_0_0::aux::enable_ifboost::msm::lite::v_1_0_0::aux::is_same<boost::msm::lite::v_1_0_0::aux::bool_list<boost::msm::lite::v_1_0_0::aux::always<TDeps::value ...>, boost::msm::lite::v_1_0_0::aux::bool_list<boost::msm::lite::v_1_0_0::aux::integral_constant<bool, __is_base_of(boost::msm::lite::v_1_0_0::aux::pool_type, typename boost::msm::lite::v_1_0_0::aux::apply<boost::msm::lite::v_1_0_0::aux::pool, typename boost::msm::lite::v_1_0_0::aux::join<typename boost::msm::lite::v_1_0_0::aux::conditional<boost::msm::lite::v_1_0_0::aux::integral_constant<bool, __is_trivially_constructible(T)>::value, boost::msm::lite::v_1_0_0::aux::type_list, boost::msm::lite::v_1_0_0::aux::type_list<SM&> >::type, typename boost::msm::lite::v_1_0_0::aux::apply<boost::msm::lite::v_1_0_0::detail::get_sub_sms, typename boost::msm::lite::v_1_0_0::aux::apply<boost::msm::lite::v_1_0_0::aux::unique_t, typename boost::msm::lite::v_1_0_0::aux::apply<boost::msm::lite::v_1_0_0::detail::get_states, decltype((declval)().configure())>::type>::type>::type, typename boost::msm::lite::v_1_0_0::aux::apply<boost::msm::lite::v_1_0_0::detail::merge_deps, decltype((declval)().configure())>::type>::type>::type)>::value ...> >::value, int>::type = 0; SM = hello_world]’
hello_world.cpp:39:24: required from here
boost/msm-lite.hpp:269:97: error: mismatched argument pack lengths while expanding ‘boost::msm::lite::v_1_0_0::aux::pool_type’
pool(init &&, pool<TArgs...> &&p) BOOST_MSM_LITE_NOEXCEPT : pool_type{aux::try_get(p)}... {}

Compiler version:
g++-6 --version

g++-6 (Debian 6.1.1-1) 6.1.1 20160430
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.