简体   繁体   English

试图写std:out并同时归档

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

I am trying to write to file and stdout at the same time within c++ by overloading ofstream 我试图通过重载流来在c ++中同时写入文件和标准输出

test.h test.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);
};

test.cpp TEST.CPP

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

The output in the file is 文件中的输出是

01400930

but in the console is 但在控制台是

test

I debugged the code it looks like it is entering into 我调试了它看起来正在进入的代码

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

What am I doing wrong? 我究竟做错了什么?

I'm not going to comment on why your approach doesn't work, mainly because it cannot be patched up to work properly. 我不打算评论为什么你的方法不起作用,主要是因为它无法修补以正常工作。 The main problem is that you can't use your stream an pass it to something which expected an std::ostream& and still write to both streams. 主要的问题是你不能使用你的流将它传递给期望std::ostream&仍然写入两个流的东西。 However, there is a relatively simple although not necessarily obvious approach to implement what you actually want: You'd derive a new stream buffer, ie, a class derived from std::streambuf , and override its overflow() and sync() functions. 但是,有一个相对简单但不一定明显的方法来实现您真正想要的东西:您将派生一个新的流缓冲区,即从std::streambuf派生的类,并覆盖其overflow()sync()函数。 Here is the complete code for a simple demo: 以下是简单演示的完整代码:

#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";
}

Obviously, the creation of tee-stream could be packaged up nicely but how this looks exactly doesn't really matter. 显然,tee-stream的创建可以很好地打包,但这看起来完全不重要。 The important thing is that it is possible to create a custom destination (or source) for IOStreams and that it does not involve any attempt to inherit from std::ostream . 重要的是,可以为IOStreams创建自定义目标(或源),并且它不涉及从std::ostream继承的任何尝试。 The only reason to inherit from std::ostream (or std::istream ) is to make the initialization of a stream with a custom stream buffer easier. std::ostream (或std::istream )继承的唯一原因是使用自定义流缓冲区初始化流更容易。

The problem 问题

 ofstream::operator << (var); 

It's your use of ofstream::operator<< as a qualified function call. 这是你使用ofstream::operator<<作为限定函数调用。 You're mandating that the function lookup locate a member function of ofstream ; 你要求函数查找定位ofstream的成员函数; the best match that's a member is the one for void* , whereas the specialisation for char* that prints the actual string contents is a free function (ie not a member function). 一个成员的最佳匹配是void* ,而打印实际字符串内容的char*是一个自由函数(即不是成员函数)。

You'll find the same problem if you do this with cout , too: 如果你用cout执行此操作,你会发现同样的问题:

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

The solution 解决方案

This might do it: 这可能会这样做:

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

because you're still using normal operator syntax (with all the overload resolution that this entails), but doing so with an ofstream as the LHS operand. 因为你仍然使用普通的运算符语法(具有所需的所有重载分辨率),但是使用ofstream作为LHS操作数。

I haven't actually tested it, though. 不过,我还没有真正测试过它。

Conclusion 结论

As an aside, your operator<< ought to be a free function too, in order to fit in with this convention. 顺便说一句, 你的 operator<<应该也是一个自由函数,以便符合这个约定。

So: 所以:

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;
};

I also took the liberty of making some minor syntax adjustments. 我也冒昧地做了一些小的语法调整。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM