2009-09-07 17 views

Respuesta

5

No puede hacerlo, realmente, pero puede fingirlo. Aquí está a way you can fake it in C, que también puede usar en C++.

+1

+1 exactamente lo que iba a decir, aunque en realidad no hay ninguna diferencia entre "simularlo" e "implementarlo". Sospecho que en C++ es posible que desee el estado coroutine en las variables miembro de un funtor, y llamar eso, con diferentes instancias cuando corresponda, en lugar de usar globales y llamar a una función nombrada como lo hace anakin. Puede hacer algo similar en C con un parámetro adicional, pero es menos probable que quiera hacerlo. –

1

Llamar a una corotina varias veces y obtener diferentes respuestas significa que mantiene un poco de estado. La forma de mantener un estado son los objetos. La forma de hacer que se vean como llamada de función es la sobrecarga del operador. Ver http://en.wikipedia.org/wiki/Function_object.

11

En C++ tenemos 'iterators'. Uno explícitamente solicita un interador, lo incrementa explícitamente y lo desreferencia.

Si desea que se utilicen con las funciones de biblioteca estándar, en su mayoría se derivan de std::forward_iterator, e implementan varias de sus funciones.

Otra manera de imitar tipode un generador en una colección es permitir que una función como argumento a una función miembro que se alimenta (rendimientos) toda ella es valores a esa función:

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

dar más detalles sobre el iterador implementación: este es un ejemplo. Se puede usar como una variable de bucle, o en algoritmos 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

El tercer parámetro del constructor 'TGenerator' debe ser' TDiff step' en lugar de 'T step'. – vvnurmi

+0

Gracias! Solucionado eso. – xtofl

1

puede utilizar boost.context (lo siento, no en la distribución impulso sin embargo, tendrá que obtener de boost vault).

Un código de ejemplo típico sería así:

#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

Este ... señores ... es pura magia NEGRO:

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

Lo he intentado, y se incluso funciona recursivamente Lo he usado regularmente desde entonces. Generadores, casi como ciudadanos de primera clase en C++. Ni siquiera hay ningún gasto de rendimiento.

Con mi más profundo respeto por el autor

+1

No es esa magia negra ... sin embargo, es muy poco C++ 11-ish. – einpoklum

Cuestiones relacionadas