Library / SDK
boost-ext/sml avatar
boost-ext/sml

boost-ext/sml: Compact C++14 State Machines in One Header

C++14 State Machine library

1,418 stars209 forksC++BSL-1.0

At a glance

What is it?
boost-ext/sml turns a C++14 transition table into a state machine for explicit control flow. It suits compact embedded and application logic, but its metaprogramming style requires close review of compiler support and build cost.
Who is it for?
Choose boost-ext/sml when the application needs an explicit state model, C++14 support, and a compact header-only integration. Do not choose it when the team prefers runtime configuration, straightforward runtime lookup, or mature tooling around another statechart representation.
Can I use it commercially?
Yes. BSL-1.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 18 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 6, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • boost-ext/sml1,418 ★ · +8
Star history
Repository2026-10-172026-11-06
boost-ext/sml1.4k1.4k

8 Stars in the last 20 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

The control-flow problem addressed by SML

boost-ext/sml is aimed at C++ developers who need state-dependent behavior without scattering boolean flags and nested branches across a class. A finite-state workflow has states, events, transition conditions, and side effects. Once enough of those rules exist, an ordinary conditional implementation becomes difficult to inspect because the legal progression is split among member functions and runtime tests. SML collects those rules into a transition table and routes each event through that table.

The README uses TCP connection release as its worked example. The modeled machine begins in an established state, moves through three states, and terminates after a timeout. Events include a release request, acknowledgements, a final message, and a timeout. Guards decide whether acknowledgement-related events are valid, while actions send protocol messages. This makes SML relevant to protocols, device workflows, UI flows, parsers, and embedded control logic, although only TCP release and other repository examples are documented here.

SML is a library for explicit finite-state behavior. It is not a general workflow engine, persistence layer, or runtime-configurable rules system. The transition model is expressed in C++ through templates, type traits, lambdas, and a domain-specific transition DSL. That makes the compile-time representation central to the library rather than an incidental packaging choice.

Transition tables, events, guards, and actions

The core mechanism is a transition table returned from a callable. States and events are encoded as types, guards and actions as C++ callables. The table's syntax follows a compact form: a source state plus an event, optionally followed by a guard and action, assigns a destination state. The initial state is marked with an asterisk, while X denotes termination.

When an application creates sm with a model and its dependencies, calls such as process_event and is expose the machine interface. In the README example, construction passes a sender dependency directly. The release event moves the machine from established to fin wait 1. An ack with valid set to true satisfies the guard and advances it to fin wait 2, while the send_ack action emits the acknowledgement. A valid fin event sends an acknowledgement and reaches timed wait. The timeout event then moves the machine to X.

This is a compile-time-defined structure with runtime state progression. The README labels process_event as O(1), so it does not document a linear scan through every transition for each event. That claim belongs to the project documentation, not to an independent benchmark.

Dependencies remain ordinary C++ objects. This matters when an action needs a sender, logging facility, or another collaborator. SML does not require that every side effect live inside the machine. The trade-off is that developers must understand how constructor injection, callable signatures, and action ordering fit together. The repository contains examples named dependencies.cpp, dependency_injection.cpp, actions_guards.cpp, and testing.cpp, but their contents are not available for closer comparison here.

Header installation and a first release workflow

The README does not document a package-manager installation. It directs users to download the latest header from include/boost/sml.hpp in the repository, then include it as boost/sml.hpp and create the namespace alias sml. Since this is a header-only project with no stated dependencies, that header is the integration surface described by the project.

For the first real use, place tcp_release.cpp beside the downloaded header in a location visible to the compiler. The complete source shown in the README declares the sender, event structs, guard, actions, transition table, and main function. Compile it with a C++14 compiler. For GCC or Clang, the documented command is:

bash
$CXX -std=c++14 -O2 -fno-exceptions -Wall -Wextra -Werror -pedantic tcp_release.cpp

The command selects C++14, optimization, disables exceptions, and treats warnings as errors. The README lists this as the GCC and Clang compile command, although the Makefile defaults CXX to g++ and supports selecting the compiler through that variable.

After a successful build, run the resulting executable from the build environment. The README documents this output for the example:

bash
send: 0
send: 42

The assertions in main also verify every state reached in the sequence. If an assertion fails, the example terminates with an assertion failure rather than printing the expected message sequence. The project README documents an MSVC command as an alternative:

bat
cl /std:c++14 /Ox /W3 tcp_release.cpp

Build and compatibility constraints around C++14

SML targets C++14, but its use of templates, generic lambdas, type traits, and expression templates makes compiler quality part of the adoption decision. The README specifically calls out MSVC-2015 compatibility. For that compiler, it says to replace string-based state literals with state<class state_name> syntax and to give lambda actions an explicit result type, written in the README as a void-returning lambda.

That caveat matters more than the nominal C++14 label. A compiler may accept the language standard while exposing errors or diagnostic behavior in code generated through template-heavy libraries. The repository's Makefile configures CMake and CTest, builds tests and examples, and supports a configurable CXXSTD variable. Its documented targets include tests for several language standards, examples, formatting checks, static analysis, Valgrind memcheck, and gcov coverage.

The central build tradeoff is between local simplicity and compile-time work. SML removes dependency installation and runtime libraries, but transition tables still become template instantiations. The README publishes compile-time and binary-size figures for specific compilers and an example, and a complex benchmark table that includes SML, enum and switch, std::variant, Boost.MSM eUML, and Boost.Statechart. Those figures are project-reported and tied to the shown cases. They should not be treated as predictions for another codebase.

A production adoption should compile the actual state model under the exact warning, exception, and optimization settings used in CI. Large event sets, nested tables, orthogonal regions, or interaction with other template libraries can affect compilation in ways the short quick-start example does not reveal.

Where SML differs from enum and switch implementations

The most direct alternative is an enum, integer, or boolean-based state variable paired with switch statements. That approach is runtime code. It is easy to inspect in a debugger, and its generated control flow may be familiar to every C++ developer. Its weakness is that transitions can become distributed across functions, leaving the legal state graph implicit.

SML takes the opposite approach. States and event types participate directly in the transition-table type, while guards and actions are separate callables. The transition declaration keeps source, event, condition, effect, and destination together. The README also lists euml_emulation.cpp among its examples, which indicates support for terminology associated with that modeling approach.

The other choices in the README benchmark are more closely related. The enum and switch implementation represents behavior with imperative branching. std::variant represents alternatives through a type container. Boost.MSM eUML and Boost.Statechart provide library-based statechart approaches. SML's practical distinction in the documented example is its one-header distribution, C++14 DSL, and compact transition declaration. Whether those differences justify adopting it depends on whether explicit graph structure matters more than the lowest possible compile-time or binary-size figure.

SML is the wrong choice for a small machine whose state logic is clearer as a direct switch. It is also a poor fit if transitions must be loaded or changed at runtime without recompiling, because the documented quick start builds the transition table as a C++ type. Do not select it merely for the benchmark figures; select it for a matching need around declarative state rules and constrained dependencies.

Maintenance, packaging, and BSL-1.0 implications

The repository is not archived, and its last push was on 2026-10-15. Release v1.2.0 is dated 2026-06-01, following v1.1.13 on 2025-12-02 and v1.1.12 on 2025-04-02. Those facts show recent project activity, but they do not answer an individual team's support or compatibility requirements.

The practical upgrade model is also unspecified. SML is delivered as one header, but the README does not document a semantic-versioning policy, backward-compatibility promise, deprecation process, or rollback procedure. A project consuming a downloaded header may therefore need to vendor a known version or track the upstream header deliberately. Pinning by release and comparing changes before replacing the header are concrete integration controls, even though the README does not prescribe either method.

SML uses the Boost Software License, Version 1.0, also identified as BSL-1.0. The README identifies that license, and the repository includes LICENSE.md along with package metadata in conanfile.py and CMake configuration files. The README does not specify redistribution instructions or compatibility with a particular organizational policy. License review should therefore be assigned to the project's normal owner rather than inferred from the header-only format.

Because SML has no listed runtime dependencies, dependency updates are smaller than for a library stack with a transitive dependency graph. The ongoing cost instead sits in compiler compatibility, transition-model readability, and keeping copied headers synchronized.

Editorial conclusion

Choose boost-ext/sml when the application needs an explicit state model, C++14 support, and a compact header-only integration. Do not choose it when the team prefers runtime configuration, straightforward runtime lookup, or mature tooling around another statechart representation. Before adoption, compile the intended transition model with the exact production compiler and flags, verify behavior for invalid or unmapped events, and review how the BSL-1.0 license fits the distribution model.

Frequently asked questions

How do I install boost-ext/sml?

The README directs users to download the latest `include/boost/sml.hpp` header. It describes SML as a dependency-free, one-header C++14 library and includes it with `<boost/sml.hpp>`.

How do I define transitions in boost-ext/sml?

Transitions are declared in `make_transition_table` with source states, `event<...>` types, optional guards, optional actions, and destination states. The initial state is marked with `*`, and `X` represents termination.

Does boost-ext/sml support MSVC-2015?

The README provides an MSVC-2015 example and compile command. It recommends using `state<class state_name>` instead of string state literals and explicitly declaring a void return type for a lambda action.

Official sources

  1. boost-ext/sml on GitHub
  2. License: BSL-1.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/boost-ext-sml.svg)](https://hysenlabs.com/projects/boost-ext-sml)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/boost-ext-sml.svg)](https://hysenlabs.com/projects/boost-ext-sml)

Was this useful?