-
Notifications
You must be signed in to change notification settings - Fork 11
Description
With state machines I'd like to encapsulate the state machine within an object - after a bunch of investigation and trial and error with sml and sml2 found the following - works best: Something along the lines of this comment: boost-ext/sml#311 (comment)
The issue I have is when I try and use lambda's
eg:
#include <sml2>
#include <iostream>
#include <chrono>
#include <fmt/chrono.h>
#include <fmt/format.h>
#include <utility>
#include <thread>
namespace phs = std::placeholders;
struct Wait
{
std::chrono::seconds duration;
};
struct Cancel
{
};
struct Expire
{
};
static std::string formatTimepoint(const std::chrono::system_clock::time_point &timePoint)
{
// Convert time_point to time_t
std::time_t time = std::chrono::system_clock::to_time_t(timePoint);
// Convert time_t to tm as local time
std::tm tm = *std::localtime(&time);
// Format the tm structure to a string using fmt::format
return fmt::format("{:%Y-%m-%d %H:%M:%S}", tm);
}
class TEBase {
public:
virtual ~TEBase() = default;
virtual void start(const Wait &ev) = 0;
};
struct SmCtx
{
SmCtx(TEBase &t)
: te(t)
{}
auto operator()()
{
using namespace sml;
using namespace sml::dsl;
// auto start = [this](const auto &ev) -> void { te.start(ev); }; // Fails
// auto start = [&](const auto &ev) -> void { te.start(ev); }; // Fails
auto start = std::bind(&TEBase::start, &te, phs::_1);
return transition_table{*"idle"_s + event<Wait> / start = "waiting"_s};
}
TEBase &te;
};
class TE : TEBase {
public:
TE()
: m_sm(SmCtx{*this})
{}
~TE() override = default;
void run() { m_sm.process_event(Wait{std::chrono::seconds(1)}); }
void start(const Wait &ev) override
{
std::cout << "Hello World at: " << formatTimepoint(std::chrono::system_clock::now()) << std::endl;
std::this_thread::sleep_for(ev.duration);
std::cout << "Just woke up at: " << formatTimepoint(std::chrono::system_clock::now()) << std::endl;
}
sml::sm<SmCtx> m_sm;
};
int main()
{
TE te;
te.run();
return 0;
}
The lambda's don't work since there is a difference in how the lambda captures this
vs the std::bind captures this
. Both will compile but when using lambda's there's a seg-fault when it tries to call the action that is the lambda.
Would be great if there's a compile-time check that a lambda isn't usable.
Also if concepts could be used to provide much easier to understand error identification when things like this are an issue. The amount of cruff
in the compile warnings are problematic for static debugging of the issues related to the state machine.