簡體   English   中英

C ++遞歸函數類型

[英]c++ recursive function type

羅布·派克提出在2011年(通話鏈接 )約在旅途中,他定義的類型這樣的詞法分析器:

// 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;

注意: 問題可能已連接(在Rust中是相同的)

編輯:

這是我想要達到的目標:

// statefn_t definition goes here ...

statefn_t* func1()
{
    return &func2;
}

statefn_t* func2()
{
    return &func1;
}

類型別名不能遞歸。

為了實現一種狀態機,例如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());
}

正如Clearer所說,這是一個C ++類型stateFn的示例,其行為類似於函數,並遞歸返回相同類型的實例。

struct stateFn
{
    stateFn& operator() ();
}

如果希望在運行時解析遞歸,同時使其與原始代碼盡可能相似,則可以使用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()()();
}

當然,這在循環中不起作用,您需要某種編譯時迭代方案才能使其有用...

這不是用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 );
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM