简体   繁体   中英

“Overriding” ostream& operator <<

I would like to implement a stringstream object which represents a stringstream of a certain type .

For instance,

class ohtmlstringstream : public std::ostringstream {
};
ohtmlstringstream& operator <<(ohtmlstringstream& ohss, double d) {
    ohss << "<div title='double'>" << d << "</div>";
    return ohss;
}

Sadly this does not work, and any ohtmlstringstream object I create which I << a double into just runs std::ostream& operator <<(std::ostream&, double) .

What's the way to do this? Looks like I should not be inheriting ostringstream.

I really just want a clean and simple way to "fork" the ways that a particular type can be serialized. For a long time I had only ever wanted to serialize a type in a single way, but now I want to build string representations of my types for at least 3 cases: In a HTML (or XML) representation, in JSON, and in the way that I already do which is something basic for dumping into the terminal while debugging.

Setting aside the general wisdom of deriving from std::ostringstream , perhaps a global

template<typename T> 
ohtmlstringstream & operator <<(ohtmlstringstream& ohss, T const & t)

in the following vein would do for you:

#include <sstream>
#include <iostream>
#include <typeinfo>

using namespace std;

class ohtmlstringstream : public ostringstream {};

template<typename T>
ohtmlstringstream & operator <<(ohtmlstringstream& ohss, T const & t)
{
    static_cast<ostringstream &>(ohss) 
        << "<div title='"
        << typeid(T).name() // For the sake of illustration
        << "'>"
        << t << 
        "</div>\n";
    return ohss;
}

// Testing ...
int main()
{
    ohtmlstringstream ohtml;
    ohtml << string("Testing") 
        << '1' << 2 << 3.0f << "4" << endl << "Bye" << endl;
    cout << ohtml.str() << endl;
    return 0;
}

Output:

<div title='Ss'>Testing</div>
<div title='c'>1</div>
<div title='i'>2</div>
<div title='f'>3</div>
<div title='A2_c'>4</div>

Bye

typeid(T).name() is doubtless not a satisfactory descriptor of T . You might replace it with custom of specializations of, say:

template<typename T>
std::string type_desc(T const &)
{
    return typeid(T).name();
}

for all T you require (resigning yourself to this much drudgery).

Note that inserting a manipulator (eg std::endl ) terminates the "html-ization", because the insertion returns a reference to the base std::ostream .

If you don't want this to happen, you would probably want the manipulator merely to be noted, but not acted upon, in the html output. So you might add the specialization:

inline ohtmlstringstream & 
operator <<(ohtmlstringstream& ohss, ostream & (*pf)(ostream &))
{
    static_cast<ostringstream &>(ohss) 
        << "<div title='"
        << typeid(pf).name()
        << "'>"
        "</div>\n";
    return ohss;
}

With this addition the output becomes:

<div title='Ss'>Testing</div>
<div title='c'>1</div>
<div title='i'>2</div>
<div title='f'>3</div>
<div title='A2_c'>4</div>
<div title='PFRSoS_E'></div>
<div title='A4_c'>Bye</div>
<div title='PFRSoS_E'></div>

(Built with gcc 4.8.2 and clang 3.3)

If you are only interested in the numeric types, you could use a custom std::num_put<...> facet to format the values. However, other types generally do not let you intercept the processing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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