1

I have a class which inherits from ofstream. I want to overload the insertion operator so that it can be a drop in repalcement for ofstream.

The first overload is

template<class T>
MyClass& Myclass::operator<<(const T& in);

and to try and handle the manipulators like std::endl

template<
    template<class, class> class Outer,
    class Inner1, 
    class Inner2
>
MyClass& Myclass::operator<<(Outer<Inner1, Inner2>& (*foo)(Outer<Inner1, Inner2>&));

If I try to compile with:

Myclass output; output << 3 << "Hi";

Then everything works fine, but when I try to add std::endl

Myclass output; output << 3 << "Hi" << std::endl;

temp.cpp: In function 'int main()':
temp.cpp:10: error: no match for 'operator<<' in '((Stream*)ss. Stream::operator<< [with T = int](((const int&)((const int*)(&3)))))->Stream::operator<< [with T = char [3]](((const char (&)[3])"Hi")) << std::endl'
/usr/include/c++/4.1.2/bits/ostream.tcc:657: note: candidates are: std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const _CharT*) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.1.2/bits/ostream.tcc:597: note:                 std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, _CharT) [with _CharT = char, _Traits = std::char_traits<char>]

I especially don't understand why in the error printout there is a const int*. This is also an attempt to learn some more about templates, but I am also trying to cover more manipulators with a single piece of code.

EDIT SSCCE:

#include <fstream>
#include <iostream>

class Myclass : public std::ofstream {
//class Stream {
    private:

    public:

        template<class T>
        Myclass& operator<<(const T& data_in) {
            std::cout << data_in;
            return *this;
        }


        template<
            template<class, class> class Outer_T, 
            class Inner_T1, 
            class Inner_T2
            >
        Myclass& operator<<(Outer_T<Inner_T1, Inner_T2>& (*foo)(Outer_T<Inner_T1, Inner_T2>&)) {
            return foo(*this);
        }

};

int main() {
    Myclass output;
    output << 3 << "Hi";
    output << 3 << "Hi" << std::endl;
}
chew socks
  • 1,406
  • 2
  • 17
  • 37
  • That code won't compile. Please post an SSCCE. – Shoe May 29 '14 at 19:00
  • `ofstream` does not have a virtual destructor. That means that the destructor of classes inheriting from `ofstream` will not be called, leading to unexpected bugs. Also the error message may be talking about the 3, not `std::endl`. – nwp May 29 '14 at 19:01
  • I'm assuming you mean compilable source, but what does SSCCEE stand for? – chew socks May 29 '14 at 19:01
  • @chewsocks [Here](http://goo.gl/KKuyvo). – Shoe May 29 '14 at 19:09
  • @Jefffrey I guess I deserved that.... I've added one now. – chew socks May 29 '14 at 19:14
  • @nwp It's been a while since I've dealt with virtual fuctions, but doesn't the lack of one just mean that you get you dynamic lookup of functions if you have code which is declared with one type and is using another? But in normal cases the destructor of inherited classes are still called after the destructor of the child? – chew socks May 29 '14 at 19:18
  • 1
    If you do something like `std::ofstream *s = new MyClass; delete s;` the destructor of `MyClass` will not be called. – nwp May 29 '14 at 19:24
  • @nwp Right, that's what I was trying to get at. Is there a good way to cause a compilation error if someone tries to do this? – chew socks May 29 '14 at 19:30
  • 1
    The "correct" way is to not inherit from `std::ofstream`. Consider giving `MyClass` a member `std::ofstream &s;` instead which can be set when constructed and defaulting to `std::cout`. – nwp May 29 '14 at 19:34
  • Take a look at [this](http://stackoverflow.com/a/1134467/3484570). – nwp May 29 '14 at 19:44
  • @nwp I think that you're probably right that that is the best way to implemenet my class. The reason that I wanted to extend `ofstream` was so that I could drop it into existing code without a lot of modification. I've seen that thread, actually. It's what I've been basing my work off of. I was hoping to find a solution that uses templates, though. That way I could be a little more comfortable that I hadn't missed any of the overloads. – chew socks May 29 '14 at 20:17

1 Answers1

1

Don't try it. The overloading of operator<< and operator>> for iostream types is complicated and messy.

What you should usually do instead is create your own std::streambuf subclass, and arrange for a standard stream class to use that. This way you can override what happens with the character stream data, without worrying about the overloaded operators, type conversion, formatting, and manipulators. For example, see James Kanze's Filtering Streambufs article, or the Boost library boost::iostreams.

aschepler
  • 70,891
  • 9
  • 107
  • 161