Generators in C++ -- invalid use of nonstatic data member
I sort of understand this, at least the function of generators (I've used them in Python). I understand how the switch statement and its content is formed. However, I get these errors.
test.cpp: In constructor 'Foo::descent::descent(int)':
test.cpp:46: error: invalid use of nonstatic data member 'Foo::index_'
test.cpp: In member function 'bool Foo::descent::operator()(std::string&)':
test.cpp:50: error: invalid use of nonstatic data member 'Foo::bars_'
test.cpp:50: error: invalid use of nonstatic data member 'Foo::index_'
test.cpp:51: error: invalid use of nonstatic data member 'Foo::index_'
test.cpp:51: error: invalid use of nonstatic data member 'Foo::bars_'
test.cpp:52: error: invalid use of nonstatic data member 'Foo::index_'
Here's the code. If you have a better way of dealing with this, by all means share please.
#include <math.h>
#include <string>
#include <vector>
#include <iostream>
#ifndef __generator_h__
#define __generator_h__
// generator/continuation for C++
// author: Andrew Fedoniouk @ terrainformatica.com
// idea borrowed from: "coroutines in C" Simon Tatham,
// http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
struct _generator
{
int _line;
_generator():_line(0) {}
};
#define $generator(NAME) struct NAME : public _generator
#define $emit(T) bool operator()(T& _rv) { \
switch(_line) { case 0:;
#define $stop } _line = 0; return false; }
#define $yield(V) \
do {\
_line=__LINE__;\
_rv = (V); return true; case __LINE__:;\
} while (0)
#endif
class Foo {开发者_Go百科
int index_;
std::vector<std::string> bars_;
public:
Foo() {
index_ = 0;
bars_.push_back("Foobar");
bars_.push_back("Barfoo");
}
$generator(descent){
int j;
descent(int j) {
index_+=j;
}
$emit(std::string)
while(true) {
$yield(bars_[index_++]);
if(index_ >= bars_.size())
index_ = 0;
}
$stop;
};
//descent bar;
void InitGenerator() { index_ = 0; }
};
using namespace std;
int main()
{
//Foo::descent gen(1);
//for(int n; gen(n);) // "get next" generator invocation
// cout << n << endl;
return 0;
}
Is this what you were after?
I'm not quite sure what you wanted the generator
to return but please modify as you wish.
The idea is that the generator object keeps it's own state and when you call method on it it gives you back next value. It is completely up to you what you define as the state and next value to be returned.
The operator()
can accept parameters, as in operator()(bool b
) or operator()(char * c)
, as well as return whatever value you want ...
#include <iostream>
#include <vector>
#include <string>
using namespace std;
struct generator
{
generator() : currentCh(0), currentW(0), str(0), words()
{ // do whatever initialization you need
words.push_back("Foobar");
words.push_back("Barfoo");
str = &words[currentW];
}
char operator()()
{ // use whatever logic you need
if (currentCh >= str->size())
{
if (++currentW >= words.size()) currentW = 0;
str = &words[currentW];
currentCh = 0;
}
return str->at(currentCh++);
}
unsigned int currentCh;
unsigned int currentW;
string * str;
vector<string> words;
};
You can update internal states anyway you like, for example add:
char operator()(unsigned int index)
{
currentCh = index;
return this->operator()();
}
Then in your code somewhere you can do:
generator g;
g(); // get first character
g(2); // resets the index in this case ...
g(); // get next character (the logic is a bit off but it depends what you need)
Usage:
int main()
{
generator g;
for (unsigned int i = 30; --i; ) cout << g() << endl;
}
Output:
F
o
o
b
a
r
B
a
r
f
o
o
F
o
o
b
a
r
B
a
r
f
o
o
F
o
o
b
a
I'm not entirely sure what you're going for here, but here's where your error is occuring:
Let's expand the macros to see how this really looks:
class Foo {
int index_;
std::vector<std::string> bars_;
public:
Foo() {
index_ = 0;
bars_.push_back("Foobar");
bars_.push_back("Barfoo");
}
struct descent: public _generator {
int j;
descent(int j) {
index_+=j;
}
bool operator()(std::string& _rv) {
switch(_line) { case 0:;
while(true) {
do {
_line=__LINE__;
_rv = (bars_[index_++]); return true; case __LINE__:;
} while (0);
if(index_ >= bars_.size())
index_ = 0;
}
} _line = 0; return false; }
};
//descent bar;
void InitGenerator() { index_ = 0; }
};
As you can see, we declare an inner structure Foo::descent
. However, unlike in some other languages, inner classes in C++ do not automatically have a pointer to an instance of their outer class. You need to either add to descent
a Foo *
which is passed in via the descent
constructor, and use that Foo *
to reference index_
and bars_
- or move the necessary members right into descent
.
To be honest, I don't really understand what Foo
here is for at all... Everything it does seems to belong right in descent
.
精彩评论