Search code examples
c++functionc++11repeatredundancy

Remove repeated code in function definition


this is my first question, so I may miss the "correct structure".

Anyway, I have a header file, with a function. This function (void readFile()) is defined in a cpp file. Within this definition I have code which repeats itself a lot.

If it was in main, I would simply declare a new function, define the repeatable in it, and then call everytime the function. But since it's in a non-main cpp file, I am having issues with this process.

Basically, what my function does, is read through a file char by char, and saves the data to different objects, based on the text.

My code looks like:

source.open("bookings.txt", std::ios::in);
char c;
source.get(c); 
            while (c != '|'){
                CurrentID.push_back(c);
                source.get(c);
            }
object.setID(CurrentID)

This code repeats itself, replacing only the line of "object.setID". I tried declaring function "search(std::ifstream x, char y, std::string z);" with definition

void Search(std::ifstream x, char y, std::string z){
    x.get(y); // next after |
    while (y != '|'){
        z.push_back(y);
        x.get(y);
    }
} 

But if I try to call this function within my "void readFile()" definition, like this:

// First block as a repeatable

source.get(c); 
            while (c != '|'){
                CurrentID.push_back(c);
                source.get(c);
            }
object->setID(CurrentID)
CurrentID.clear();

// second block as a function, with repeatable code commented out

void Search(std::ifstream quelle, char c, std::string &CurrentID);

            /* source.get(c); 
            while (c != '|'){
                CurrentID.push_back(c);
                source.get(c);
            }*/
            object->setPrice(stof (CurrentID));
            CurrentID.clear();

It jumps from "CurrentID.clear()" in first block, directly to "object->setPrice" in second block, ignoring the existence of the void Search function. Any proposition how to make the function work, or maybe other way, to remove repeated code?


Solution

  • I don't know if this will exactly answer your question. If not, please post your entire code, especially the readFile function.

    Let's say you want a readFile function to:

    • parse an input stream, and
    • fill the fields ID (string) and price (float) of a list of object structs,
    • the values in the stream being separated by a | character, and,
    • using a second function readToken for the repeated code (i.e., read from the input stream until the separator is found and return a string).

    The code below does that. Notice:

    • you define readFile and readToken as separate functions, and
    • both change the state of the input stream.

    [Demo]

    #include <iostream>
    #include <sstream>
    #include <string>  // stof
    #include <vector>
    
    struct object {
        std::string id;
        float price;
    };
    
    std::string readToken(std::istringstream& iss) {
        std::string ret{};
        char c{};
        while (true) {
            iss >> c;
            if (not iss.eof() and c != '|') {
                ret.push_back(c);
            } else {
                return ret;
            }
        }
    }
    
    std::vector<object> readFile(std::istringstream& iss) {
        std::vector<object> ret{};
        while (not iss.eof()) {
            auto id = readToken(iss);
            auto price = std::stof(readToken(iss));
            ret.emplace_back(id, price);
        }
        return ret;
    }
    
    int main() {
        std::istringstream input{"ID1|25.5|ID2|3.14"};
        auto objects = readFile(input);
        for (const auto& o : objects) {
            std::cout << o.id << ", " << o.price << "\n";
        }
    }
    
    
    // Outputs:
    //
    //   ID1, 25.5
    //   ID2, 3.14
    

    A simpler way to do this would be to have std::getline read tokens:

    [Demo]

    std::vector<object> readFile(std::istringstream& iss) {
        std::vector<object> ret{};
        while (not iss.eof()) {
            std::string id{};
            std::getline(iss, id, '|');
    
            std::string price_str{};
            std::getline(iss, price_str, '|');
            auto price = std::stof(price_str);
    
            ret.emplace_back(id, price);
        }
        return ret;
    }