В C ++, как построить объект, ссылающийся на другой объект istream, в зависимости от условий выполнения? - PullRequest
1 голос
/ 16 января 2020

Я хочу создать объект, который читает из файла или с консоли. Если есть аргумент командной строки, предполагается, что этот аргумент является именем файла, и код будет считан из файла. В противном случае код будет считываться со стандартной консоли cin. Поскольку оба объекта ifstream и cin являются производными от istream, я хотел бы сохранить в классе ссылку istream& либо на объект ifstream, либо на cin. Ниже приведен код класса:

#include <iostream>
#include <fstream>
#include <sstream>

class Reader {
public:
    Reader(std::istream& is) : is(is) {}
private:
    std::istream& is;
};

Но я столкнулся с проблемой при попытке создать такой объект в соответствии с условиями во время выполнения. Попытка выглядит следующим образом:

int main(int argc, char *argv[]) {
    if (argc > 1) {  //read from file
        std::ifstream in_f(argv[1]);
        if (in_f)
            LineReader reader(in_f);
    }
    else {  //read from console (standard input)
        LineReader reader(std::cin);
    }

    //work on reader ...

    return 0;
}

Дело в том, что объект Reader создается в условном выражении. Он исчезнет после того, как казнь погаснет. Но мне нужно, чтобы этот объект проделал большую работу после его строительства. Поэтому я должен определить объект Reader вне условия, но я не вижу способа инициализировать его перед условием. Я также не знаю, как «назначить» ссылку на istream после инициализации, потому что ссылка не может быть изменена. Обратите внимание, что класс istream не может быть скопирован. Не могли бы вы научить меня, как написать класс Reader, если я хочу сохранить ссылку на istream и инициализировать ее в соответствии с условиями во время выполнения? Моя идея состоит в том, что код для обработки ввода, либо из консоли, либо из файла, точно такой же. Я хочу повторно использовать одну переменную для представления входного потока другого типа. Спасибо.

PS: я использую C ++ 11, и код будет работать как в Windows, так и в Ubuntu.

1 Ответ

2 голосов
/ 16 января 2020

Вы можете просто создать функцию для // work on reader:

void do_work(LineReader& reader)
{
    // work on reader
}


int main(int argc, char *argv[]) {
    if (argc > 1) {  //read from file
        std::ifstream in_f(argv[1]);
        if (in_f) {
            LineReader reader(in_f);
            do_work(reader);
        }
    }
    else {  //read from console (standard input)
        LineReader reader(std::cin);
        do_work(reader);
    }
}

или реорганизовать свой код, чтобы получить ссылку на std::istream:

std::istream& get_istream(std::ifstream& in_f, int argc, char* argv[])
{
    if (argc > 1) {  //read from file
        in_f.open(argv[1]);
    }
    if (in_f) {
        return in_f;
    } else {
        return std::cin;
    }
}


int main(int argc, char *argv[]) {
    std::ifstream in_f;
    LineReader reader(get_istream(in_f, argc, argv));

    // work on reader
}
...