Я хочу знать, как реализовать генератор, например Python, на C++? Python может использовать ключевое слово «доходность» для этого. Но как это сделать на С++?
Как реализовать генератор на С++?
Ответы (6)
В C++ у нас есть «итераторы». Один явно запрашивает интератор, явно увеличивает его и разыменовывает.
Если вы хотите, чтобы они использовались со стандартными библиотечными функциями, они в основном должны быть производными от std::forward_iterator
и реализовывать ряд его функций.
Другой способ имитировать вид генератора в коллекции - разрешить функцию в качестве аргумента функции-члену, которая передает (выдает) все свои значения этой функции:
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() );
Это... господа... чистая ЧЕРНАЯ МАГИЯ:
http://www.codeproject.com/Articles/29524/Generators-in-C
Я пробовал это, и это даже работает рекурсивно. С тех пор я использую его регулярно. Генераторы, почти как граждане первого класса в C++. Нет даже накладных расходов на производительность.
С глубоким уважением к автору
Вы не можете сделать это, на самом деле, но вы можете притворяться. Вот способ, которым вы можете подделать это в C, который вы можете использовать на С++ тоже.
Чтобы уточнить реализацию итератора: это пример. Его можно использовать как переменную цикла или в стандартных алгоритмах.
#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;
}
Многократный вызов сопрограммы и получение разных ответов означает, что вы сохраняете какое-то состояние. Способ сохранить состояние — это объекты. Способ сделать их похожими на вызов функции — это перегрузка оператора. См. http://en.wikipedia.org/wiki/Function_object.
вы можете использовать boost.context (извините, пока нет в Boost-дистрибутиве, вам придется получить его с расширить хранилище).
Типичный пример кода будет таким:
#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);
}