2013-06-23 13 views
7

Czy w języku C++ jest możliwe utworzenie funkcji zwracającej funktora z tym samym podpisem co funkcja?jak utworzyć funkcję, która zwraca funktor z tym samym podpisem co funkcja?

zasadniczo, jak zalegalizować decltype(foo) foo();.

lub z funktorów: function<function<function<...(void)>(void)>(void)>

Chciałbym to wykorzystać do państwowego maszynie gdzie każdy stan jest funkcją, która zwraca funktor do następnego stanu obiektu. Mam teraz wprowadziły go przy użyciu stałe teksty, ale czuję, że musi być lepszy sposób:

#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(); 
} 

także: czy istnieje sposób mniej przylegający do wyrażenia pytanie?

+0

Dlaczego piszesz kod maszynowy w C++ zamiast VHDL? –

+3

Ponieważ mówię o abstrakcji matematycznej, a nie o prawdziwej maszynie. –

+0

To zależy od tego, co masz na myśli przez "powrót". Funktory zachowują się jak funty w pewien sposób, więc kompilator nadal oceni wartość funktora przed zwróceniem czegokolwiek, więc skończy się rekurencją. –

Odpowiedz

7

Można złamać typu rekursji owijając funkcję w 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; 
} 

UPDATE: po komentarzach Yakk ('uczynić go bardziej ogólne') i Luc Danton ("Classic GOTW") I dodam bardziej ogólną wersję C++ 11 poniżej, która jest oparta na wersji 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

Znacznie poprawiłby to 'operator()'. – Yakk

+0

@Yakk, Masz rację. dodano operatora. _And_ dzięki za dodanie const ... – dhavenith

+0

Jedyne inne zmiany, które mogą mnie kusić, powodują, że 'std :: string' to' template' arg. Och i doskonałe przekazywanie w twoim 'operator()'. – Yakk

Powiązane problemy