我在一个类中实现了一个非常小的有限状态机,我最初的方法是尝试这个:
class Widget {
public:
void update(float time_interval){
current_state = current_state_(time_interval);
}
private:
std::function< ?? > off_(float);
std::function< ?? > standby_(float);
std::function< ?? > locked_(float);
std::function< ?? > current_state_; // initialised to off_
};
每个州都是一个返回状态的函数。但我无法弄清楚如何声明一个返回类型包含其返回类型的函数。有没有办法打破递归?
相反,我使用了enum class
和丑陋的switch
语句。
答案 0 :(得分:4)
如果我理解正确,你想返回一个函数引用到状态链中的下一个函数,并且所有状态步骤函数都有相同的签名?
我看到这里的问题是返回类型是函数本身,因此声明函数的类型会调用递归类型定义。
所以你想编写RetType fn_(float)
形式的函数,但RetType的类型是(基本上)RetType fn_(float)
。所以现在我们有(RetType (*)(float)) fn_(float)
或类似的东西,但是我们努力尝试我们无法摆脱RetType。
如果没有向前声明某些内容,您无法关闭该递归。我们可以转发声明类,并使用它们,所以让我们为你的函数指针编写一个简单的类包装器,这可能是@Jarod所暗示的。现在,std :: function是函数的类包装器,但它需要显式类型声明,我们没有。
class Widget;
class StateFn;
class StateFn
{
Widget * THIS;
StateFn (Widget::*Fn)(float);
public:
/// Or you could rely on POD construction
StateFn(Widget * THIS, StateFn (Widget::*Fn)(float))
: THIS(THIS), Fn(Fn)
{}
StateFn operator()(float f)
{
return THIS->*fn(f);
}
};
所以现在递归定义被破坏了,我们的状态函数可以返回StateFn对象,我们可以调用它们。
答案 1 :(得分:0)
我找到了一个解决方案 - 使用std::unordered_map
代替丑陋的switch
:
class Widget {
public:
enum class State { Off, Standby, Locked };
void update(float time_interval) {
current_state_ = (this->*state_fn_.at(state_))(time_interval);
}
private:
State off_(float) {return ::has_power() ? State::Standby : State::Off;}
State standby_(float);
State locked_(float);
const std::unordered_map<State, State(Widget::*)(float)> state_fn_{
{State::Off, &Widget::off_},
{State::Standby, &Widget::standby_},
{State::Locked, &Widget::locked_}};
State current_state_{State::Off};
};
只有1 + 3n行代码比我在问题中提出的理想代码更差 - 我对此非常满意!