尝试同时写入 std:out 和文件

trying to write std:out and file at the same time

本文关键字:out 文件 std      更新时间:2023-10-16

我试图通过重载流在 c++ 中同时写入文件和标准输出

测试.h

 #pragma once 
#include <iostream>
using  std::ofstream;
class OutputAndConsole:public ofstream
{
public:
    std::string fileName;        
    OutputAndConsole(const std::string& fileName):ofstream(fileName),fileName(fileName){
    };
    template <typename T>
    OutputAndConsole& operator<<(T var);
};

template <typename T>
OutputAndConsole& OutputAndConsole::operator<<(T var)
{
    std::cout << var;
    ofstream::operator << (var);
    return (*this);
};

测试.cpp

  OutputAndConsole file("output.txt");
  file << "test" ;

文件中的输出是

01400930

但在控制台中是

test

我调试了它看起来像是进入的代码

_Myt& __CLR_OR_THIS_CALL operator<<(const void *_Val)

我做错了什么?

我不打算评论为什么你的方法不起作用,主要是因为它无法修补以正常工作。主要问题是你不能使用你的流,把它传递给一个预期std::ostream&的东西,并且仍然写入两个流。但是,有一种相对简单但不一定明显的方法来实现您真正想要的东西:您将派生一个新的流缓冲区,即从std::streambuf派生的类,并覆盖其overflow()sync()函数。下面是一个简单演示的完整代码:

#include <streambuf>
struct teebuf
    : std::streambuf
{
    std::streambuf* sb1_;
    std::streambuf* sb2_;
    teebuf(std::streambuf* sb1, std::streambuf* sb2)
        : sb1_(sb1), sb2_(sb2) {
    }
    int overflow(int c) {
        typedef std::streambuf::traits_type traits;
        bool rc(true);
        if (!traits::eq_int_type(traits::eof(), c)) {
            traits::eq_int_type(this->sb1_->sputc(c), traits::eof())
                && (rc = false);
            traits::eq_int_type(this->sb2_->sputc(c), traits::eof())
                && (rc = false);
        }
        return rc? traits::not_eof(c): traits::eof();
    }
    int sync() {
        bool rc(true);
        this->sb1_->pubsync() != -1 || (rc = false);
        this->sb2_->pubsync() != -1 || (rc = false);
        return rc? 0: -1;
    }
};
#include <fstream>
#include <iostream>
int main()
{
    std::ofstream fout("tee.txt");
    teebuf        sbuf(fout.rdbuf(), std::cout.rdbuf());
    std::ostream  out(&sbuf);
    out << "hello, world!n";
}

显然,tee-stream的创建可以很好地打包,但这看起来如何并不重要。重要的是,可以为IOStreams创建自定义目标(或源),并且它不涉及任何尝试从std::ostream继承。从std::ostream(或std::istream)继承的唯一原因是使使用自定义流缓冲区初始化流更容易。

问题

ofstream::operator << (var);

这是您使用ofstream::operator<<作为限定函数调用。您要求函数查找查找 ofstream 的成员函数;成员的最佳匹配是void*,而打印实际字符串内容的char*专用化是一个自由函数(即不是成员函数)。

如果您使用cout执行此操作,您也会发现同样的问题:

std::cout.operator<<(var);

解决方案

这可能会做到:

static_cast<ofstream&>(*this) << var;

因为您仍在使用正常的运算符语法(具有这所需的所有重载分辨率),但使用ofstream作为 LHS 操作数。

不过,我还没有真正测试过它。

结论

顺便说一句,您的operator<<也应该是一个自由功能,以便适应此约定。

所以:

struct OutputAndConsole : std::ofstream
{
    OutputAndConsole(const std::string& fileName)
       : std::ofstream(fileName)
       , fileName(fileName)
    {};
    const std::string fileName;
};
template <typename T>
OutputAndConsole& operator<<(OutputAndConsole& strm, const T& var)
{
    std::cout << var;
    static_cast<std::ofstream&>(strm) << var;
    return strm;
};

我还冒昧地做了一些小的语法调整。