Is it possible to use movable-only state machine with SML?
Hi! Consider the following example:
#include <boost/sml.hpp>
#include <cassert>
#include <iostream>
#include <variant>
#include <mutex>
namespace sml = boost::sml;
namespace {
struct connect {};
struct disconnect {};
class data {
struct Disconnected {};
struct Connected {
int id{};
};
public:
explicit data(const std::string& address) : address{address} {}
inline auto operator()() {
using namespace boost::sml;
return make_transition_table(
* state<Disconnected> + event<connect> / [this] {
data_ = Connected{42};
} = state<Connected>
, state<Connected> + event<disconnect> / [this] {
std::cout << std::get<Connected>(data_).id << std::endl;
} = X
);
}
private:
std::mutex mutex;
std::string address{};
std::variant<Disconnected, Connected> data_{};
};
} // namespace
int main() {
sml::sm<data> sm{data{"127.0.0.1"}};
sm.process_event(connect{});
sm.process_event(disconnect{});
assert(sm.is(sml::X));
}
If you try to compile: you will get something like this: https://pastebin.com/rYbdrbL8
I cannot be compiled since std::mutex is movable only type.
My question is: is it possible avoid such limitation with SML library? If yes, how can I do it?
std::mutex is neither copyable nor movable.
Sorry, my bad. Of course you are right. What about the following sample?
#include <boost/sml.hpp>
#include <cassert>
#include <iostream>
#include <variant>
#include <mutex>
namespace sml = boost::sml;
namespace {
struct connect {};
struct disconnect {};
struct type
{
type() = default;
type(const type&) = delete;
type(type&&) = default;
int a;
};
class data {
struct Disconnected {};
struct Connected {
int id{};
};
public:
explicit data(const std::string& address) : address{address} {}
inline auto operator()() {
using namespace boost::sml;
return make_transition_table(
* state<Disconnected> + event<connect> / [this] {
data_ = Connected{42};
} = state<Connected>
, state<Connected> + event<disconnect> / [this] {
std::cout << std::get<Connected>(data_).id << std::endl;
} = X
);
}
private:
type t;
std::string address{};
std::variant<Disconnected, Connected> data_{};
};
} // namespace
int main() {
sml::sm<data> sm{data{"127.0.0.1"}};
sm.process_event(connect{});
sm.process_event(disconnect{});
assert(sm.is(sml::X));
}
Should probably work fine with perfect forwarding used in aux::pool and aux::pool_type, but I'm not familiar enough with SML guts to be 100% sure. You may try to add it here:
explicit pool_type(T object) : value{object} {}
And here:
explicit pool(Ts... ts) : pool_type<Ts>(ts)... {}
Maybe it would also require making aux::pool movable itself.