Генераторы в C ++ — недопустимое использование нестатического элемента данных

StackOverflow https://stackoverflow.com/questions/1604699

  •  05-07-2019
  •  | 
  •  

Вопрос

Я вроде как понимаю это, по крайней мере, функцию генераторов (я использовал их в Python).Я понимаю, как формируется оператор switch и его содержимое.Однако я получаю эти ошибки.

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_'

Вот код.Если у вас есть лучший способ справиться с этим, обязательно поделитесь, пожалуйста.

#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 {
    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;
}
Это было полезно?

Решение

Я не совсем уверен, что вы собираетесь здесь, но здесь, где ваша ошибка происходит:

Давайте расширим макросы, чтобы увидеть, как это выглядит на самом деле:

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; }
};

Как видите, мы объявляем внутреннюю структуру Foo :: descent . Однако, в отличие от некоторых других языков, внутренние классы в C ++ не имеют автоматически указателя на экземпляр своего внешнего класса. Вам нужно либо добавить в descent Foo * , который передается через конструктор descent , и использовать этот Foo * для ссылки на index _ и bars _ - или переместите необходимые элементы прямо в спуск .

Честно говоря, я не совсем понимаю, для чего здесь вообще нужен Foo ... Кажется, все, что он делает, относится прямо к descent .

Другие советы

Это то, чего ты добивался?

Я не совсем уверен, чего вы хотели от меня. generator вернуть, но, пожалуйста, измените по своему усмотрению.

Идея заключается в том, что объект generator сохраняет свое собственное состояние, и когда вы вызываете для него метод, он возвращает вам следующее значение.Это полностью зависит от вас, что вы определяете как состояние и следующее значение, которое должно быть возвращено.

Тот Самый operator() может принимать параметры, как в operator()(bool b) или operator()(char * c), а также возвращайте любое значение , которое вы хотите...

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

Вы можете обновлять внутренние состояния любым удобным вам способом, например добавлять:

char operator()(unsigned int index)
{
    currentCh = index;
    return this->operator()();
}

Затем в вашем коде где-нибудь вы можете сделать:

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)

Использование:

int main()
{
    generator g;
    for (unsigned int i = 30; --i; ) cout << g() << endl;
}

Выходной сигнал:

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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top