从 C++ 中的标准输入或文件透明读取?

Transparent read from stdin or a file in C++?

我想解析 stdin 流或文件。所以我想要一个 function/method 来接受其中任何一个。

请注意,我的目标不是调用 read 两次!

因为 istreamcin and ifstream 的基础 class 我应该可以这样写:

#include <iostream>
#include <fstream>

void read(std::istream &fp) {
    while(!fp.eof()) {
        std::string line;
        std::getline(fp, line);
        std::cout << line << std::endl;;
    }
}

int main(int argc, char *argv[])
{
    std::ifstream fp;

    if (argc >= 2) {
        fp.open(argv[1]);
        if (!fp) abort();
    }
    else {
        fp = std::cin;
    }
    
    read(fp);

    if (fp.is_open()) {
        fp.close();
    }
    return 0;
}

在 C 中,我可以使用 read_content(stdin)read_content(fp) 调用它来执行以下操作:

void read_content(FILE *file)

在 C++ 中执行此操作的正确方法是什么?

In C I can do the following with calling it with either read_content(stdin) or read_content(fp):

是的,在 C++ 中,您应该只调用 read(std::cin) read(fp)。一模一样

fp = std::cin;

是错误的做法,因为 std::cin 仅声明为 std::istream。没有采用 istream 的 std::ifstream 构造函数,无论如何你都不想要一个独立的对象,如果 std::cin 确实是从 std::ifstream 派生的某种类型的对象,你会切片它。

std::cinstd::istream 的一个实例,而不是从 std::ifstream 派生的,但恰恰相反。

基于Stream的继承图I/O:

(摘自cppreference.com - Input/output library

因此,可以使用指向 std::istream 的引用或指针来执行 OP 意图。

演示:

#include <iostream>
#include <fstream>

void read(std::istream &fp) {
    while(!fp.eof()) {
        std::string line;
        std::getline(fp, line);
        std::cout << line << std::endl;;
    }
}

int main(int argc, char *argv[])
{
    std::ifstream fp;
    std::istream &in = (argc >= 2)
      ? [&]() -> std::istream& {
        fp.open(argv[1]);
        if (!fp) abort();
        return fp;
      }()
      : std::cin;
    
    read(in);

    if (fp.is_open()) {
        fp.close();
    }
    return 0;
}

Compiled on coliru


注:

    while (!fp.eof()) {

应替换为

    while (fp) {

其原因已在
中进行了彻底讨论 SO: Why is iostream::eof inside a loop condition (i.e. while (!stream.eof())) considered wrong?.