Search code examples
pythonc++functionyieldtranslate

translate python function with yield(string) to C++


I'm translating a python function into a C++ function; this function uses a yield(string) statement that I don't know how to translate.

Here the whole story...I have a certain function that reads an input ASCII file filename, which contains lines of data, and puts the content of the file into an std::vector. When reading this input file (in another function respect with the one showed below), I need to jump a bunch of lines (5 or 6, it depends on the input file's name) and, for this purpose, I define a function, the file_struct_generator, which marks as "data" the data lines and as "unused" the data lines I don't need. I need something similar to this function in C++, and in particular, I need something similar to yield(string) (pay attention, string!), but in C++ of course. Here I show you the lines of the code I need to "translate" from python to C++. How can I rewrite yield("unused") and yield("data") in C++? Or if yield is unusable in C++, can I write a similar function in C++ using something different which works as a generator? Thanks for helping me!

def file_struct_generator(filename):
    if "more" in filename:
        bad_line_number = 5
    else:
        bad_line_number = 6

    yield("data")
    for i in range(bad_line_number):
        yield("unused")
    while True:
        yield("data")
    

EDIT: I do not use C++20, but C++11. I tried @Arthur Tacca code and it works for my purpose, thank you all.


Solution

  • This is a state machine that reproduces that generator's functionality.

    #include <stdexcept>
    #include <string>
    #include <iostream>
    
    class FileStructIterator {
    public:
        explicit FileStructIterator(const std::string& filename): 
            m_filename(filename), m_state(STATE_START) 
        {}
    
        std::string getNext() {
            switch (m_state) {
            case STATE_START:
                m_state = STATE_LOOP1;
                if (m_filename.find("more") != std::string::npos) {
                    m_badLineNumber = 5;
                } else {
                    m_badLineNumber = 6;
                }
                m_i = 0;
                return "data";
    
            case STATE_LOOP1:
                ++m_i;
                if (m_i >= m_badLineNumber) {
                    m_state = STATE_LOOP2;
                }            
                return "unused";
    
            case STATE_LOOP2:
                return "data";
    
            default:
                throw std::logic_error("bad state");
            }
        }
    
    private:
        std::string m_filename;
    
        enum State { STATE_START, STATE_LOOP1, STATE_LOOP2 };
        State m_state;
    
        size_t m_badLineNumber;
        size_t m_i;
    };
    

    Here's an example of using it (in this case I limited the output to the first 10 results so it doesn't loop forever).

    int main() {
        auto it = FileStructIterator("nomore.txt");
        for (int i = 0; i < 10; ++i) {
            std::string nextValue = it.getNext();
            std::cout << nextValue << "\n";
        }
    }