Rob Pike在2011年(link)发表了一篇关于lexers的演讲, 在那里他定义了这样的类型:
// stateFn represents the state of the scanner
// as a function that returns the next state.
type stateFn func() stateFn
我想在C ++中实现相同目标,但无法弄清楚:
// 01: error C3861: 'statefn_t': identifier not found
typedef std::function<statefn_t()> statefn_t;
// 02: error C2371: 'statefn_t': redefinition; different basic types
typedef std::function<class statefn_t()> statefn_t;
// 03: error C2371: 'statefn_t': redefinition; different basic types
typedef std::function<struct statefn_t()> statefn_t;
// 04: error C2065: 'statefn_t': undeclared identifier
typedef std::function<statefn_t*()> statefn_t;
// 05: error C2371: 'statefn_t': redefinition; different basic types
typedef std::function<class statefn_t*()> statefn_t;
// 06: error C2371: 'statefn_t': redefinition; different basic types
typedef std::function<struct statefn_t*()> statefn_t;
注意:this问题可能已连接(在Rust中相同)
修改
这是我想要实现的目标:
// statefn_t definition goes here ...
statefn_t* func1()
{
return &func2;
}
statefn_t* func2()
{
return &func1;
}
答案 0 :(得分:4)
类型别名不能递归。
要实现状态机,例如go讲座中使用的状态机,您需要定义自定义类型:
class state
{
public:
using fn = std::function<state()>;
state() {}
state(fn f) : f(f){}
operator bool() { return (bool)f; }
operator fn () { return f; }
private:
fn f;
};
用法:
state::fn stateEnd()
{
std::cout << "end\n";
return {};
}
state::fn stateTransit()
{
std::cout << "transit\n";
return stateEnd;
}
state::fn stateStart()
{
std::cout << "start\n";
return stateTransit;
}
int main() {
state::fn s = stateStart;
while(s = s());
}
替代形式:
class state
{
public:
state() {}
template<class T>
state(T&& t) : f(std::forward<T>(t)){}
operator bool() { return (bool)f; }
state operator()() { return f(); }
private:
std::function<state()> f;
};
用法:
state stateEnd()
{
std::cout << "end\n";
return {};
}
state stateTransit()
{
std::cout << "transit\n";
return stateEnd;
}
state stateStart()
{
std::cout << "start\n";
return stateTransit;
}
int main() {
state s {stateStart};
while(s = s());
}
答案 1 :(得分:1)
正如Clearer评论的那样,这里是一个C ++类型stateFn
的例子,它的行为类似于一个函数,并递归地返回一个相同类型的实例。
struct stateFn
{
stateFn& operator() ();
}
答案 2 :(得分:1)
如果你想在运行时解析递归,同时保持它与原始代码尽可能相似,你可以使用boost :: any或C ++ 17 std :: any,如:
std::any end(){ std::cout << "end\n"; return {}; }
std::any state(){ std::cout << "some state\n"; return &end; }
std::any begin(){ std::cout << "begin\n"; return &state; }
void advance( std::any& state )
{ state = std::any_cast<std::any(*)()>(state)(); }
int main()
{
for( auto state = begin(); state.has_value(); advance( state ) );
}
如果必须在编译时解析递归,则可以利用自动类型推导:
auto end(){ std::cout << "end\n"; }
auto state(){ std::cout << "some state\n"; return &end; }
auto begin(){ std::cout << "begin\n"; return &state; }
int main()
{
begin()()();
}
当然,这在循环中不起作用,你需要某种编译时迭代方案才能使它有用......
答案 3 :(得分:0)
用C ++做事并不是一种自然的方法。
在C ++中,它更像是混淆,这反映在为状态推进函数找到良好的自描述名称的困难中,这些函数也是状态:
struct Context {};
class State
{
using F = auto( Context const& ) -> State;
F* next_state_;
public:
auto is_finished() const -> bool { return next_state_ == nullptr; }
auto operator()( Context const& ctx ) const
-> State
{ return next_state_( ctx ); }
State( F* f ): next_state_{ f } {}
inline State();
};
auto intermediate( Context const& ) { return State{ nullptr }; }
auto start( Context const& ) { return State{ intermediate }; }
State::State(): next_state_{ start } {}
#include <iostream>
using namespace std;
auto main() -> int
{
State state;
Context ctx;
cout << boolalpha;
for( ;; )
{
cout << state.is_finished() << endl;
if( state.is_finished() ) { break; }
state = state( ctx );
}
}