2009-09-07 21 views

risposta

5

Non puoi farlo, davvero, ma puoi fingere. Ecco lo a way you can fake it in C, che puoi usare anche in C++.

+1

+1 esattamente quello che stavo per dire, anche se non c'è davvero alcuna differenza tra "finirlo" e "implementarlo". Sospetto che in C++ si possa desiderare lo stato di coroutine nelle variabili membro di un functor e chiamarlo, con istanze diverse dove appropriato, invece di usare globals e chiamare una funzione con nome come fa anakin. Puoi fare una cosa simile in C con un parametro extra, ma è meno probabile che lo desideri. –

1

Chiamare una coroutine più volte e ottenere risposte diverse significa mantenere uno stato. Il modo per mantenere uno stato sono gli oggetti. Il modo per farli sembrare chiamata di funzione è l'overloading dell'operatore. Vedi http://en.wikipedia.org/wiki/Function_object.

11

In C++ abbiamo "iteratori". Uno chiede esplicitamente un interatore, lo accresce esplicitamente e lo denota.

Se si desidera che vengano utilizzati con le funzioni di libreria standard, dovrebbero essere principalmente derivati ​​da std::forward_iterator e implementare un numero di sue funzioni.

Un altro modo per imitare kindof un generatore su una collezione sta permettendo una funzione come argomento di una funzione di membro che si nutre (rendimenti) tutti i suoi valori a quella funzione:

struct MyCollection { 
    int values[30]; 

    template< typename F > 
    void generate(F& yield_function) const { 
     int* end = values+30; // make this better in your own code :) 
     for(auto i: values) yield_function(*i); 
    } 
}; 

// usage: 
c.generate([](int i){ std::cout << i << std::endl; }); 

// or pre-C++11: 
struct MyFunction { 
    void operator() (int i)const { printf("%d\n", i); } 
}; 
MyCollection c; 
c.generate(MyFunction()); 
5

Per approfondire l'iteratore implementazione: questo è un esempio. Può essere usato come variabile di ciclo o in algoritmi std.

#include <iterator> 

template< typename T, typename TDiff = T > 
struct TGenerator : public std::iterator<std::forward_iterator_tag,T,TDiff> { 
    T from,to; 
    T value; 
    TDiff step; 
    bool issentinel; 

    TGenerator(T from, T to, TDiff step, bool sentinel = false) 
    : from(from),to(to),step(step),issentinel(sentinel), value(from) 
    {} 

    void operator++(){ value += step; } 

    const T& operator*()const { return value; } 

    bool operator!=(const TGenerator& other) const { 
    return value<to; 
    } 

    TGenerator sentinel()const { return TGenerator(0,0,0,true); } 

}; 


#include <algorithm> 
#include <iostream> 

int main() 
{ 
    TGenerator<int> i(0,10,3); 
    std::copy(i, i.sentinel(), std::ostream_iterator<int>(std::cout, " ")); 

    return 0; 
} 
+0

Il terzo parametro del costruttore 'TGenerator' dovrebbe essere' TDiff step' invece di 'T step'. – vvnurmi

+0

Grazie! Risolto il problema. – xtofl

1

è possibile utilizzare boost.context (spiacente, non sulla distribuzione spinta ancora, dovrete ottenere da boost vault).

Un codice tipico esempio potrebbe essere simile a questo:

#include <iostream> 
#include <boost/context.hpp> 

using namespace std; 

struct Parameters { 
    int par1; 
    float par2; 
}; 

boost::context c1; 
boost::context c2; 

void F(void* parameters) { 
    Parameters& pars = *(Parameters*)parameters; 
    cout << pars.par1 << endl; 
    c2.jump_to(c1); 
    cout << pars.par2 << endl; 
}; 

int main() { 
    c1 = boost::context::current(); 
    Parameters p; 
    p.par1 = 8; 
    c2 = boost::context::create_context(F , c1 , p); 
    c1.jump_to(c2); 
    p.par2 = 1.3; 
    c1.jump_to(c2); 
} 
8

Questa ... Signori ... è pura MAGIA NERA:

http://www.codeproject.com/Articles/29524/Generators-in-C

ho provato, ed è funziona anche in modo ricorsivo. L'ho usato regolarmente da allora. Generatori, quasi come cittadini di prima classe in C++. Non c'è nemmeno un sovraccarico di prestazioni.

Con il mio più profondo rispetto all'autore

+1

Non è _that_ black magic ... tuttavia, è molto un-C++ 11-ish. – einpoklum

Problemi correlati