模板基础 class 实现默认实现
Template base class implementation a default implementation
我正在尝试制作一个简单的模板化 FSM 库,它将允许:machine.react(Event1{});
调用实现 SomeState.react(std::shared_ptr<StateMachine> machine, Event1 event)
而无需提前知道所有可能的事件,无需实现所有 Derived class 的所有可能事件。
当我从 current_state_ 调用存储为 State
类型的函数时,当调用 react(不是虚拟的)时,它将调用 Base 实现而不是 Derived (State1) class实施。
#include <iostream>
#include <memory>
#include <tuple>
#include <typeinfo>
#include <vector>
template <typename ContextT, typename... StatesT>
class MachineT : public std::enable_shared_from_this<MachineT<ContextT, StatesT...>> {
using M_ = MachineT<ContextT, StatesT...>;
public:
using Context = ContextT;
class State {
public:
template <typename EVENT>
void react(std::shared_ptr<M_> machine, EVENT event) {
std::cout << "State::react" << std::endl;
};
virtual void update(std::shared_ptr<M_> machine) = 0;
};
MachineT(std::shared_ptr<ContextT> context)
: context_(context),
states_{std::make_shared<StatesT>()...} {
using FirstEntityType = std::tuple_element_t<0, std::tuple<StatesT...>>;
set<FirstEntityType>();
}
~MachineT() {}
template <typename T>
std::shared_ptr<T> get() {
return std::get<std::shared_ptr<T>>(states_);
}
template <typename T>
void set() {
current_state_ = std::get<std::shared_ptr<T>>(states_);
}
std::shared_ptr<M_> shared() {
return this->shared_from_this();
}
void update(){
current_state_->update(shared());
};
template <typename EVENT>
void react(EVENT event){
current_state_->react(shared(), event);
};
private:
std::shared_ptr<ContextT> context_;
std::tuple<std::shared_ptr<StatesT>...> states_;
std::shared_ptr<State> current_state_;
};
struct State1;
struct State2;
struct Context {};
struct Event1 {};
using StateMachine = MachineT<Context, State1, State2>;
struct State1 : public StateMachine::State {
int value = 10;
void print() { std::cout << value << std::endl; }
void react(std::shared_ptr<StateMachine> machine, Event1 event) {
std::cout << "State1::react()" << std::endl;
}
void update(std::shared_ptr<StateMachine> machine) {
std::cout << "State1::update()" << std::endl;
}
};
struct State2 : public StateMachine::State {
int value = 20;
void print() { std::cout << value << std::endl; }
void react(std::shared_ptr<StateMachine> machine, Event1 event) {
std::cout << "State2::react()" << std::endl;
}
void update(std::shared_ptr<StateMachine> machine) {
std::cout << "State2::update()" << std::endl;
}
};
int main() {
std::shared_ptr<Context> context;
context.reset(new Context());
std::shared_ptr<StateMachine> machine;
machine.reset(new StateMachine(context));
machine->set<State1>();
machine->update();
machine->react(Event1{});
machine->set<State2>();
machine->update();
machine->react(Event1{});
}
完整示例:http://cpp.sh/7d37rq
当前输出:
State1::update()
State::react()
State2::update()
State::react()
预期输出:
State1::update()
State1::react()
State2::update()
State2::react()
你需要 std::variant
并将当前状态存储为:
std::variant<std::shared_ptr<StatesT>...> current_state_;
具有检测给定状态是否对某些事件类型作出反应的特征:
template <typename State, typename Event, typename = void>
struct can_react : std::false_type {};
template <typename State, typename Event>
struct can_react<State, Event,
decltype(void(std::declval<State>()->react(nullptr, std::declval<Event>())))>
: std::true_type {};
然后,如果状态可以处理,则可以将事件发送到状态,否则丢弃:
template <typename Event>
void react(Event event) {
std::visit([&](auto state) {
if constexpr (can_react<decltype(state), Event>{}) {
state->react(shared(), event);
}
}, current_state_);
}
同样,update
变为:
void update() {
std::visit([this](auto state) {
state->update(shared());
}, current_state_);
}
完整代码:
template <typename ContextT, typename... StatesT>
class MachineT : public std::enable_shared_from_this<MachineT<ContextT, StatesT...>> {
using M_ = MachineT<ContextT, StatesT...>;
public:
using Context = ContextT;
MachineT(std::shared_ptr<ContextT> context)
: context_(context),
states_{std::make_shared<StatesT>()...} {
using FirstEntityType = std::tuple_element_t<0, std::tuple<StatesT...>>;
set<FirstEntityType>();
}
~MachineT() {}
template <typename T>
std::shared_ptr<T> get() {
return std::get<std::shared_ptr<T>>(states_);
}
template <typename T>
void set() {
current_state_ = std::get<std::shared_ptr<T>>(states_);
}
std::shared_ptr<M_> shared() {
return this->shared_from_this();
}
void update() {
std::visit([this](auto state) { state->update(shared()); }, current_state_);
}
template <typename State, typename Event, typename = void>
struct can_react : std::false_type {};
template <typename State, typename Event>
struct can_react<State, Event,
decltype(void(std::declval<State>()->react(nullptr, std::declval<Event>())))>
: std::true_type {};
template <typename Event>
void react(Event event) {
std::visit([&](auto state) {
if constexpr (can_react<decltype(state), Event>{}) {
state->react(shared(), event);
}
}, current_state_);
}
private:
std::shared_ptr<ContextT> context_;
std::tuple<std::shared_ptr<StatesT>...> states_;
std::variant<std::shared_ptr<StatesT>...> current_state_;
};
状态和事件:
struct State1;
struct State2;
struct Context {};
struct Event1 {};
struct Event2 {};
using StateMachine = MachineT<Context, State1, State2>;
struct State1 {
void react(std::shared_ptr<StateMachine> machine, Event1 event) {
std::cout << "State1::react(Event1)" << std::endl;
}
void update(std::shared_ptr<StateMachine> machine) {
std::cout << "State1::update()" << std::endl;
}
};
struct State2 {
void react(std::shared_ptr<StateMachine> machine, Event2 event) {
std::cout << "State2::react(Event2)" << std::endl;
}
void update(std::shared_ptr<StateMachine> machine) {
std::cout << "State2::update()" << std::endl;
}
};
测试:
int main() {
std::shared_ptr<Context> context;
context.reset(new Context());
std::shared_ptr<StateMachine> machine;
machine.reset(new StateMachine(context));
machine->set<State1>();
machine->update();
machine->react(Event1{});
machine->set<State2>();
machine->update();
machine->react(Event2{});
}
输出:
State1::update()
State1::react(Event1)
State2::update()
State2::react(Event2)
使用c++14 it's possible using boost::variant
:
template <typename Event>
struct Visitor {
MachineT* machine;
Event* event;
template <typename State>
std::enable_if_t<can_react<State, Event>{}> operator()(State state) const {
state->react(machine->shared(), *event);
}
template <typename State>
std::enable_if_t<!can_react<State, Event>{}> operator()(State) const {}
};
template <typename Event>
void react(Event event) {
boost::apply_visitor(Visitor<Event>{ this, &event }, current_state_);
}
我正在尝试制作一个简单的模板化 FSM 库,它将允许:machine.react(Event1{});
调用实现 SomeState.react(std::shared_ptr<StateMachine> machine, Event1 event)
而无需提前知道所有可能的事件,无需实现所有 Derived class 的所有可能事件。
当我从 current_state_ 调用存储为 State
类型的函数时,当调用 react(不是虚拟的)时,它将调用 Base 实现而不是 Derived (State1) class实施。
#include <iostream>
#include <memory>
#include <tuple>
#include <typeinfo>
#include <vector>
template <typename ContextT, typename... StatesT>
class MachineT : public std::enable_shared_from_this<MachineT<ContextT, StatesT...>> {
using M_ = MachineT<ContextT, StatesT...>;
public:
using Context = ContextT;
class State {
public:
template <typename EVENT>
void react(std::shared_ptr<M_> machine, EVENT event) {
std::cout << "State::react" << std::endl;
};
virtual void update(std::shared_ptr<M_> machine) = 0;
};
MachineT(std::shared_ptr<ContextT> context)
: context_(context),
states_{std::make_shared<StatesT>()...} {
using FirstEntityType = std::tuple_element_t<0, std::tuple<StatesT...>>;
set<FirstEntityType>();
}
~MachineT() {}
template <typename T>
std::shared_ptr<T> get() {
return std::get<std::shared_ptr<T>>(states_);
}
template <typename T>
void set() {
current_state_ = std::get<std::shared_ptr<T>>(states_);
}
std::shared_ptr<M_> shared() {
return this->shared_from_this();
}
void update(){
current_state_->update(shared());
};
template <typename EVENT>
void react(EVENT event){
current_state_->react(shared(), event);
};
private:
std::shared_ptr<ContextT> context_;
std::tuple<std::shared_ptr<StatesT>...> states_;
std::shared_ptr<State> current_state_;
};
struct State1;
struct State2;
struct Context {};
struct Event1 {};
using StateMachine = MachineT<Context, State1, State2>;
struct State1 : public StateMachine::State {
int value = 10;
void print() { std::cout << value << std::endl; }
void react(std::shared_ptr<StateMachine> machine, Event1 event) {
std::cout << "State1::react()" << std::endl;
}
void update(std::shared_ptr<StateMachine> machine) {
std::cout << "State1::update()" << std::endl;
}
};
struct State2 : public StateMachine::State {
int value = 20;
void print() { std::cout << value << std::endl; }
void react(std::shared_ptr<StateMachine> machine, Event1 event) {
std::cout << "State2::react()" << std::endl;
}
void update(std::shared_ptr<StateMachine> machine) {
std::cout << "State2::update()" << std::endl;
}
};
int main() {
std::shared_ptr<Context> context;
context.reset(new Context());
std::shared_ptr<StateMachine> machine;
machine.reset(new StateMachine(context));
machine->set<State1>();
machine->update();
machine->react(Event1{});
machine->set<State2>();
machine->update();
machine->react(Event1{});
}
完整示例:http://cpp.sh/7d37rq
当前输出:
State1::update()
State::react()
State2::update()
State::react()
预期输出:
State1::update()
State1::react()
State2::update()
State2::react()
你需要 std::variant
并将当前状态存储为:
std::variant<std::shared_ptr<StatesT>...> current_state_;
具有检测给定状态是否对某些事件类型作出反应的特征:
template <typename State, typename Event, typename = void>
struct can_react : std::false_type {};
template <typename State, typename Event>
struct can_react<State, Event,
decltype(void(std::declval<State>()->react(nullptr, std::declval<Event>())))>
: std::true_type {};
然后,如果状态可以处理,则可以将事件发送到状态,否则丢弃:
template <typename Event>
void react(Event event) {
std::visit([&](auto state) {
if constexpr (can_react<decltype(state), Event>{}) {
state->react(shared(), event);
}
}, current_state_);
}
同样,update
变为:
void update() {
std::visit([this](auto state) {
state->update(shared());
}, current_state_);
}
完整代码:
template <typename ContextT, typename... StatesT>
class MachineT : public std::enable_shared_from_this<MachineT<ContextT, StatesT...>> {
using M_ = MachineT<ContextT, StatesT...>;
public:
using Context = ContextT;
MachineT(std::shared_ptr<ContextT> context)
: context_(context),
states_{std::make_shared<StatesT>()...} {
using FirstEntityType = std::tuple_element_t<0, std::tuple<StatesT...>>;
set<FirstEntityType>();
}
~MachineT() {}
template <typename T>
std::shared_ptr<T> get() {
return std::get<std::shared_ptr<T>>(states_);
}
template <typename T>
void set() {
current_state_ = std::get<std::shared_ptr<T>>(states_);
}
std::shared_ptr<M_> shared() {
return this->shared_from_this();
}
void update() {
std::visit([this](auto state) { state->update(shared()); }, current_state_);
}
template <typename State, typename Event, typename = void>
struct can_react : std::false_type {};
template <typename State, typename Event>
struct can_react<State, Event,
decltype(void(std::declval<State>()->react(nullptr, std::declval<Event>())))>
: std::true_type {};
template <typename Event>
void react(Event event) {
std::visit([&](auto state) {
if constexpr (can_react<decltype(state), Event>{}) {
state->react(shared(), event);
}
}, current_state_);
}
private:
std::shared_ptr<ContextT> context_;
std::tuple<std::shared_ptr<StatesT>...> states_;
std::variant<std::shared_ptr<StatesT>...> current_state_;
};
状态和事件:
struct State1;
struct State2;
struct Context {};
struct Event1 {};
struct Event2 {};
using StateMachine = MachineT<Context, State1, State2>;
struct State1 {
void react(std::shared_ptr<StateMachine> machine, Event1 event) {
std::cout << "State1::react(Event1)" << std::endl;
}
void update(std::shared_ptr<StateMachine> machine) {
std::cout << "State1::update()" << std::endl;
}
};
struct State2 {
void react(std::shared_ptr<StateMachine> machine, Event2 event) {
std::cout << "State2::react(Event2)" << std::endl;
}
void update(std::shared_ptr<StateMachine> machine) {
std::cout << "State2::update()" << std::endl;
}
};
测试:
int main() {
std::shared_ptr<Context> context;
context.reset(new Context());
std::shared_ptr<StateMachine> machine;
machine.reset(new StateMachine(context));
machine->set<State1>();
machine->update();
machine->react(Event1{});
machine->set<State2>();
machine->update();
machine->react(Event2{});
}
输出:
State1::update()
State1::react(Event1)
State2::update()
State2::react(Event2)
使用c++14 it's possible using boost::variant
:
template <typename Event>
struct Visitor {
MachineT* machine;
Event* event;
template <typename State>
std::enable_if_t<can_react<State, Event>{}> operator()(State state) const {
state->react(machine->shared(), *event);
}
template <typename State>
std::enable_if_t<!can_react<State, Event>{}> operator()(State) const {}
};
template <typename Event>
void react(Event event) {
boost::apply_visitor(Visitor<Event>{ this, &event }, current_state_);
}