c++ 状态机状态的函数调用需要返回相同类型的函数指针

mec1mxoz  于 2023-05-20  发布在  其他
关注(0)|答案(1)|浏览(135)

我正在用Visual C++ '22编写一个状态机,将每个状态表示为一个函数,每个状态确定并返回一个指向其下一个状态的函数指针。虽然我的代码基于编辑器的语法检查似乎是正确的,并且如果从函数调用中删除函数指针参数(不再可以构造状态机),它可以工作,但实际编译给了我一个语法错误;还有一大堆的错误这是一个编译器错误还是我只是编码错误?
下面是我的测试代码。

typedef void (*myfnptr)(__int64& val, myfnptr& nextState);

void aFn(__int64& val, myfnptr& nextState )
{
    val = 7;
    nextState = &bFn;
}

void bFn(__int64& val, myfnptr& nextState)
{
    val = 9;
    nextState = &aFn;
 }

int main()
{
    __int64 val;
    myfnptr fn = &aFn;
    myfnptr nextState;
    fn(val, nextState);
    nextState(val, nextState);
}

而“typedef”行的错误C2061语法错误:标识符'myfnptr'...
我假设这个问题是由于typedef中定义的循环性造成的,但是我看不到有任何方法可以绕过这种循环性,这样的定义对于定义状态机很重要,其中状态被实现为函数并作为函数指针传递,而不是在状态机的更高级别上使用switch语句和枚举。

42fyovps

42fyovps1#

复合类型在C++中不能无限深地嵌套,typedef不会创建新类型,而只是别名另一个类型。因此,不能编写一个函数类型,它将typedef艾德别名作为参数的一部分,这将导致类型无限递归并嵌套在自身上。
相反,通过编写一个类来将函数指针 Package 为成员,从而形成一个实际上新的独特类型。这个类类型可以在函数类型中用作参数:

struct NextState;

typedef void (*myfnptr)(__int64& val, NextState& nextState);
// or, probably easier to read:
// using myfnptr = void (*)(__int64&, NextState&);

struct NextState {
    myfnptr ptr;

    // A constructor so that you can assign/initialize
    // with a raw function pointer directly.
    // Without it you need to assign explicitly to
    // nextState.ptr or use brace initialization/assignment.
    NextState(myfnptr ptr_) : ptr(ptr_) {};

    // A conversion function to the raw pointer type,
    // so that nextState can be called directly as
    // nextState(/*...*/)
    // Without it you need to write nextState.ptr(/*...*/).
    operator myfnptr() { return ptr; }
};

void aFn(__int64& val, NextState& nextState )
{
    val = 7;
    nextState = &bFn;
}

void bFn(__int64& val, NextState& nextState)
{
    val = 9;
    nextState = &aFn;
 }

int main()
{
    __int64 val;
    NextState nextState = &aFn;
    // no need for `fn` here
    nextState(val, nextState);
    nextState(val, nextState);
}

考虑使用std::int64_t而不是__int64。前者是标准化的(从C11开始),在所有支持这种类型的C实现中,它会给予你一个64位宽的有符号整数类型,而__int64是特定于编译器的。
(我不评论状态机的设计选择是否是一个好的选择,因为这似乎超出了范围。有许多其他的方法可以做到这一点,这可能是更好的方法。)

相关问题