2013-06-23 13 views
7

E 'possibile in C++ creare una funzione che restituisca un funtore con la stessa firma della funzione?come creare una funzione che restituisce un funtore con la stessa firma della funzione?

in modo semplice, come legalizzare decltype(foo) foo();.

o con functors: function<function<function<...(void)>(void)>(void)>

Mi piacerebbe usare questo per uno stato-macchina in cui ogni stato è una funzione che restituisce un funtore al successivo stato dell'oggetto. Ora ho implementato utilizzando le enumerazioni, ma mi sento come ci deve essere un modo migliore:

#include <iostream> 
using namespace std; 

enum functionenum{END,FOO,BAR,BAZ}; 

functionenum foo(){ 
    cout<<"FOO! > "; 
    string s; 
    cin>>s; 
    if(s=="end") return END; 
    if(s=="bar") return BAR; 
       return FOO; 
} 

functionenum bar(){ 
    cout<<"BAR! > "; 
    string s; 
    cin>>s; 
    if(s=="end") return END; 
    if(s=="baz") return BAZ; 
       return BAR; 
} 

functionenum baz(){ 
    cout<<"BAZ! > "; 
    string s; 
    cin>>s; 
    if(s=="end") return END; 
    if(s=="bar") return BAR; 
    if(s=="foo") return FOO; 
       return BAZ; 
} 

void state(){ 
    auto f=foo; 
    while(true){ 
     switch (f()){ 
     case FOO: f=foo; break; 
     case BAR: f=bar; break; 
     case BAZ: f=baz; break; 
     case END: return; 
     }; 
    }; 
} 

int main(){ 
    state(); 
} 

anche: c'è un modo meno goffo per formulare la domanda?

+0

Perché stai scrivendo codice macchina di stato in C++ anziché VHDL? –

+3

Perché sto parlando dell'astrazione matematica e non di una macchina reale. –

+0

Beh, dipende da cosa intendi per "ritorno". I Funcitors si comportano come le funtions in un certo modo, quindi il compilatore valuterà comunque il valore del functor prima di restituire qualsiasi cosa in modo da finire con la ricorsione. –

risposta

7

Si potrebbe rompere il tipo ricorsione avvolgendo la funzione in una struct:

#include <string> 

struct state 
{ 
    typedef state (*state_func)(const std::string &); 
    state(state_func f): function(f){} //not explicit, for notational convenience 
    state operator()(const std::string&arg) const 
    { 
     return function(arg); 
    } 
private: 
    state_func function; 

}; 

state f(const std::string &); 
state g(const std::string &) 
{ 
    return &f; 
} 
state f(const std::string &) 
{ 
    return &g; 
} 

int main() 
{ 
    state s(&f); 
    s = s("hello"); 
    return 0; 
} 

AGGIORNAMENTO: dopo i commenti di Yakk ('renderlo più generico') e Luc Danton ("Classic GOTW") I Sto aggiungendo una versione più generica di C++ 11, che si basa sulla versione GOTW.

/// Type that wraps functions that return functions with the same signature. 
template<typename... Arguments> 
struct SelfReturningFunction 
{ 
    typedef SelfReturningFunction (*FunctionPointer)(Arguments...); 
    SelfReturningFunction(FunctionPointer f): function(f){} 
    operator FunctionPointer() const 
    { 
     return function; 
    } 
private: 
    FunctionPointer function; 
}; 

// example usage 
#include <string> 

using state = SelfReturningFunction<const std::string&>; 

state f(const std::string &); 
state g(const std::string &) 
{ 
    return &f; 
} 
state f(const std::string &) 
{ 
    return &g; 
} 
state dead_end(const std::string &) 
{ 
    return &dead_end; 
} 

int main() 
{ 
    state s{&f}; 
    s = s("hello"); 
    return 0; 
} 
+0

Questo sarebbe molto migliorato da quel 'operator()'. – Yakk

+0

@Yakk, hai ragione. aggiunto l'operatore. _End_ grazie per aver aggiunto il const ... – dhavenith

+0

Le uniche altre modifiche che potrei essere tentato sono la creazione di 'std :: string' a' template' arg. Oh e perfetto inoltro nel tuo operatore() '. – Yakk

Problemi correlati