我有一些趋于像一个简单状态机的代码。这些是我拥有的对象:
class Actions
{
public:
enum Action {
action1,
action2,
action3
};
typedef void(*DoAction)(int);
static void Start(int type) {
}
static void Stop(int type) {
}
static void NoAction(int type) {
}
};
struct ActionCallback
{
Actions::Action action;
Actions::DoAction callback;
ActionCallback(Actions::Action a, Actions::DoAction c) :action(a), callback(c) { }
ActionCallback() : action(Actions::action1), callback(Actions::NoAction) { }
};
这里有一个Actions
对象,它定义了事件和回调,还有一个ActionCallback
对象,它包含一个动作和一个回调。
下面是我的StateMachine
类-为简单起见,它使用int's
作为状态:
struct StateMachine {
using StateMachineMap = std::map<std::pair<int, int>, ActionCallback>;
StateMachineMap m_stateMachineMap;
StateMachine() {
m_stateMachineMap[std::make_pair(1, 2)] = ActionCallback(Actions::Action::action1, Actions::Start);
m_stateMachineMap[std::make_pair(1, 3)] = ActionCallback(Actions::Action::action2, Actions::Stop);
m_stateMachineMap[std::make_pair(1, 4)] = ActionCallback(Actions::Action::action3, Actions::Start);
m_stateMachineMap[std::make_pair(1, 5)] = ActionCallback(Actions::Action::action3, Actions::Stop);
m_stateMachineMap[std::make_pair(1, 6)] = ActionCallback(Actions::Action::action2, Actions::Start);
m_stateMachineMap[std::make_pair(1, 7)] = ActionCallback(Actions::Action::action1, Actions::NoAction);
}
void performAction(Actions::Action action) {
}
};
这是我的主类,它将包含状态机并调用performAction
:
class Device {
StateMachine stateMachine;
public:
void TakeControl(int type) {
}
void ReleaseControl(int type) {
}
void NoAction(int type) {
}
};
我真正想要的是:是否可以通过这种设计将Device
方法作为回调传递,而不是传递Actions
类的静态方法?
类似这样的东西:
m_stateMachineMap[std::make_pair(1, 2)] = ActionCallback(Actions::Action::action1, Device::Start); // will trigger Device::Start to be called
现在,我觉得Device
使用StateMachine
和Actions
的{{1}}和StateMachine
使用Device
的实例是错误的。
答案 0 :(得分:1)
类型void(*)(int)
(别名为Actions::DoAction
)和类型void(Device::*)(int)
(&Device::TakeControl
等)之间是有区别的。
请注意,您都需要 和Device
和int
来调用后者。幸运的是,您可以改编ActionCallback
来使用它。
struct ActionCallback
{
using DeviceCall = void(Device::*)(Actions::Action);
Actions::Action action = Actions::action1;
DeviceCall callback = &Device::NoAction;
void operator()(Device * device) { (device.*callback)(action); }
};
我们已经定义了operator()
,因此可以像函数一样调用ActionCallback
的实例
struct StateMachine {
using StateMachineMap = std::map<std::pair<int, int>, ActionCallback>;
StateMachineMap m_stateMachineMap;
StateMachine() {
m_stateMachineMap[std::make_pair(1, 2)] = ActionCallback{Actions::Action::action1, &Device::Start};
m_stateMachineMap[std::make_pair(1, 3)] = ActionCallback{Actions::Action::action2, &Device::Stop};
m_stateMachineMap[std::make_pair(1, 4)] = ActionCallback{Actions::Action::action3, &Device::Start};
m_stateMachineMap[std::make_pair(1, 5)] = ActionCallback{Actions::Action::action3, &Device::Stop};
m_stateMachineMap[std::make_pair(1, 6)] = ActionCallback{Actions::Action::action2, &Device::Start};
m_stateMachineMap[std::make_pair(1, 7)] = ActionCallback{Actions::Action::action1, &Device::NoAction};
}
void performAction(std::pair<int, int> what, Device * who) {
m_stateMachineMap[what](who);
}
};
还存在一种类型,该类型可以概括具有给定签名std::function
的任何可调用对象。
如果将Actions::Action
与Device *
一起传递,则可以使用
using ActionCallback = std::function<void(Device *, Actions::Action)>;
StateMachineMap m_stateMachineMap { { std::make_pair(1, 2), &Device::Start } };
但是,您要将特定的Action
与回调相关联。 Lambda可以捕获调用时要使用的值。
using DeviceCall = void(Device::*)(Actions::Action);
using ActionCallback = std::function<void(Device *)>;
ActionCallback make_action_callback(Actions::Action action, DeviceCall callback)
{
return [=](Device * device){ (device.*callback)(action); };
}
StateMachineMap m_stateMachineMap { { std::make_pair(1, 2), make_action_callback(Actions::action1, &Device::Start) } };