IO-manipulators as template parameters? - c++

I'm trying to work with a class, let's call it a stream_wrapper.
It contains a value of (or a reference to) an std::ostream object as one of its fields.
All I want to do is to overload the << operator, so I can use this wrapper like a normal stream.
My first idea was just to write it as a function template.
Example:
class stream_wrapper
{
std::ostream& stream;
template<typename Output>
friend stream_wrapper& operator<<(stream_wrapper& s, Output output)
public:
stream_wrapper(std::ostream& stream) : stream(stream) {}
}
template<typename Output>
stream_wrapper& operator<<(stream_wrapper& s, Output output)
{
s.stream << output;
return s;
}
The idea was that template will be instantiated fine for all types that std::ostream's operator<< works.
This works fine with all usual types, but fails when I attempt to pass some stream manipulator, such as std::endl.
Example:
int main()
{
stream_wrapper s(std::cout);
int a = 1;
double b = 5;
s << a << ' ' << b << '\n'; // WORKS
s << std::endl; // DOESN'T COMPILE
}
This fails, because the compiler can't deduce the type of std::endl.
So, my questions are:
Is there a way to make it work?
What type things like std::endl are?
Thank you!

First off, your overloaded operator<< is missing a return *this; statement.
Second, I/O manipulators are implemented as functions that take a stream object as input. For example, std::endl is declared like this:
template< class CharT, class Traits >
std::basic_ostream<CharT, Traits>& endl( std::basic_ostream<CharT, Traits>& os );
std::basic_ostream has an overloaded operator<< which accepts such a function:
basic_ostream& operator<<(
std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&) );
This overload of std::basic_ostream::operator<< will call the func() with *this as the input parameter, eg:
basic_ostream& operator<<(
std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&) )
{
return func(*this);
}
This mechanism is what allows std::endl (and other manipulators) to be used with any std::ostream object via operator<<.
So, in your example, s << std::endl does not compile because std::endl is expecting a std::ostream object, not a stream_wrapper object.
To fix this in your wrapper, you will have to add extra overloads of operator<< to handle the various kinds of I/O manipulators that are available, eg:
class stream_wrapper
{
std::ostream& stream;
template<typename Output>
friend stream_wrapper& operator<<(stream_wrapper&, const Output &);
friend stream_wrapper& operator<<(stream_wrapper&, std::ios_base& (*)(std::ios_base&) );
friend stream_wrapper& operator<<(stream_wrapper&, std::ios& (*)(std::ios&) );
friend stream_wrapper& operator<<(stream_wrapper&, std::ostream& (*)(std::ostream&) );
public:
stream_wrapper(std::ostream& stream) : stream(stream) {}
}
template<typename Output>
stream_wrapper& operator<<(stream_wrapper& s, const Output &output)
{
s.stream << output;
return *this;
}
stream_wrapper& operator<<(stream_wrapper& s, std::ios_base& (*func)(std::ios_base&) )
{
s.stream << func;
// or: func(s.stream);
return *this;
}
stream_wrapper& operator<<(stream_wrapper& s, std::ios& (*func)(std::ios&) )
{
s.stream << func;
// or: func(s.stream);
return *this;
}
stream_wrapper& operator<<(stream_wrapper& s, std::ostream& (*func)(std::ostream&) )
{
s.stream << func;
// or: func(s.stream);
return *this;
}

Related

ostream: how are functions being called for this chained output?

Can anyone explain how the following iostream cout code is evaluated with each specific function including its declaration? Also, how the hex manipulator modifies the stream flags (my guess is it calls ios.flags()). For instance, I'm looking at ostream member functions and non member functions and am confused on what is being called and the order of evaluation (I think there is no specified order).
#include <iostream>
using namespace std;
int main()
{
int v = 0xFF;
cout << "0x" << hex << v << endl;
return 0;
}
std::hex and std::endl are standalone functions that take a std::ios_base& and std::basic_ostream& as input, respectively:
std::ios_base& hex( std::ios_base& str );
template< class CharT, class Traits >
std::basic_ostream<CharT, Traits>& endl( std::basic_ostream<CharT, Traits>& os );
These functions manipulate the given stream as needed:
std::hex() calls the stream's setf() method to enable the std::ios_base::hex flag on it.
std::endl() writes a line break to the stream and then flushes the stream.
std::basic_ostream has non-static member operator<< overloads which take those kind of functions as input:
basic_ostream& operator<<(
std::ios_base& (*func)(std::ios_base&) );
basic_ostream& operator<<(
std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&) );
These operator<< overloads simply call the given function with *this as input, and then return *this to the caller.
There is also a non-static member operator<< overload for taking an int as input:
basic_ostream& operator<<( int value );
This overload writes the int value to this, and then returns *this to the caller.
However, there is no non-static member operator<< overload for taking a string literal as input, but there are standalone non-member operator<< overloads for that:
template< class CharT, class Traits >
basic_ostream<CharT,Traits>& operator<<( basic_ostream<CharT,Traits>& os,
const CharT* s );
template< class CharT, class Traits >
basic_ostream<CharT,Traits>& operator<<( basic_ostream<CharT,Traits>& os,
const char* s );
template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,
const char* s );
These overloads write the char* data to os, and then return os to the caller.
So, the expression:
cout << "0x" << hex << v << endl;
Ends up being evaluated like this:
operator<<(cout, "0x").operator<<(hex).operator<<(v).operator<<(endl);

How operator<< works with manipulator functions

In C++ is possible to write code like this:
cout << std::endl;
where, std::endl is a function that will be called with cout as a parameter. I'm wondering is it special feature of << and >> operators or there is a generic rule that allows to do same thing with other operators (for example with +)?
There is nothing really special about this. std::ostream::operator<< is simply overloaded to accept various types in input.
In the case of manipulator functions, operator<< is overloaded to accept certain types of function pointers as input by default:
basic_ostream& operator<<(
std::ios_base& (*func)(std::ios_base&) );
basic_ostream& operator<<(
std::basic_ios<CharT,Traits>& (*func)(std::basic_ios<CharT,Traits>&) );
basic_ostream& operator<<(
std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&) );
And then the implementations of those overloads just call whatever function is passed in to them, specifying *this as the function's input parameter, eg:
basic_ostream& basic_ostream::operator<<(std::ios_base& (*func)(std::ios_base&) )
{
(*func)(*this);
return *this;
}
basic_ostream& basic_ostream::operator<<(std::basic_ios<CharT,Traits>& (*func)(std::basic_ios<CharT,Traits>&))
{
(*func)(*this);
return *this;
}
basic_ostream& basic_ostream::operator<<(std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&))
{
(*func)(*this);
return *this;
}
Thus cout << std::endl; is simply calling cout.operator<<(std:endl);, where std::endl() matches the 3rd overload above:
template< class CharT, class Traits >
std::basic_ostream<CharT, Traits>& endl( std::basic_ostream<CharT, Traits>& os );
In the case of the stream manipulator functions in the <iomanip> header, the manipulators that do not take any input parameters from user's code (ie std::boolalpha, std::showbase, etc) are usually implemented as standalone functions that match one of the overloads above, and thus DO get passed the ostream/istream directly as a parameter. However, the manipulators that take input parameters from user code (ie std::resetiosflags(), std::setbase(), etc) are defined to return "unspecified" (ie implementation-defined) types, where their implementations define additional overloads of operator<< and operator>> for those types so they can receive the ostream/istream to manipulate, respectively.
For example: std::fill might be implemented something like this:
template< class CharT >
struct fill_t { CharT ch; };
template< class CharT >
fill_t setfill( CharT c )
{
return fill_t<CharT>{c};
}
template< class CharT >
basic_ostream& operator<<(basic_ostream& out, const fill_t &in)
{
out.fill(in.ch);
return out;
}
Thus cout << setfill(' ') calls the equivalent of fill_t tmp = setfill(' '); operator<<(cout, tmp);
There is nothing special going on here. std::istream and std::ostream have overloads for the operator >> and operator << respectively in the form of
basic_istream& operator>>( std::ios_base& (*func)(std::ios_base&) );
basic_istream& operator>>( std::basic_ios<CharT,Traits>& (*func)(std::basic_ios<CharT,Traits>&) );
basic_istream& operator>>( basic_istream& (*func)(basic_istream&) );
basic_ostream& operator<<( std::ios_base& (*func)(std::ios_base&) );
basic_ostream& operator<<( std::basic_ios<CharT,Traits>& (*func)(std::basic_ios<CharT,Traits>&) );
basic_ostream& operator<<( std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&) );
that allow the class to take a function pointer as the right hand side of the operator. When doing
cout << std::endl;
std::endl decays into a function pointer and the correct overload is called. You can do this with any operator for any type you have.
If you do plan to do this, think about the principal of least surprise, i.e don't use a common syntax that has a completely different meaning and use that as your custom overload.
You sure can.
#include <iostream>
struct Foo
{
int f = 0;
};
Foo operator+(Foo foo, int (*function)())
{
return {foo.f + function()};
}
int one()
{
return 1;
}
int main(int argc, const char* argv[])
{
Foo foo {10};
std::cout << (foo+one).f << std::endl;
}
Output:
11

Any shortcut to providing identical ostream and wostream stream operators?

I want to provide ostream<< and wostream<< operators for a class, which are identical other than one being widestream and the other not.
Is there some trickery to do this which is ugly than just copy-pasting and making the necessary tweaks?
For reference, this is necessary because we use wostream as standard, but Google-test's EXPECT_PRED3 fails compilation when no ostream<< is provided, even though other macros happily work with ostream or wostream.
My actual code looks like this:
class MyClass
{
...
public:
friend std::wostream& operator<<(std::wostream& s, const MyClass& o)
{
...
}
};
std::ostream and std::wostream are just specializations of a template class std::basic_ostream. Writing a templated operator << shall solve your problem. Here's an example:
struct X { int i; };
template <typename Char, typename Traits>
std::basic_ostream<Char, Traits> & operator << (std::basic_ostream<Char, Traits> & out, X const & x)
{
return out << "This is X: " << x.i << std::endl;
}
As pointed out in comments, you can go even further and parametrize your operator << by any class that exposes some stream-like interface:
template <typename OStream>
OStream & operator << (OStream & out, X const & x)
{
return out << "This is X: " << x.i << std::endl;
}

operator overloading is breaking functions unexpectantly

Ambiguous overload for operator<<() is called when I add the overload function below
template <typename Container> ostream& operator<<(ostream& os, const Container& c)
{
copy(c.begin(), c.end(), ostream_iterator<typename Container::value_type>(os, " "));
return os;
}
the error is called on this function where it uses the <<.
void print_list(const list<int>& list_int)
{
for (list<int>::const_iterator it = list_int.begin(); it != list_int.end(); it++) cout << *it << " ";
}
(For reference, if anyone else is looking: http://ideone.com/YlX7q )
Your definition of operator<< can be instantiated as ::operator<<<int>(std::ostream&, const int&); this is ambigious with std::operator<<(std::ostream&, int). Calling the name of the type Container doesn't mean it is a container; overload resolution is done before the definition is instantiated.
Yes of course this cannot work.
You are introducing a templated overload, and the compiler don't know anymore what to use when you use that operator.
Simply you cannot do that.
You can do something like this:
template<class T>
friend ostream& operator<<(ostream& os, const MyClass<T>& r);
but you cannot do
template<class T>
friend ostream& operator<<(ostream& os, const T& r);

Boost.Test output_test_stream fails with templated output operator

I have a class:
class foo {
private:
std::string data;
public:
foo &append(const char* str, size_t n) { data.append(str,n); }
// for debug output
template <typename T>
friend T& operator<< (T &out, foo const &f);
// some other stuff
};
template <typename T>
T& operator<< (T &out, foo const &f) {
return out << f.data;
}
I want this to work with any class that provides the << operator.
This works fine with std::cout as in:
std::cout << fooObject;
But the following fails:
BOOST_AUTO_TEST_CASE( foo_append_and_output_operator )
{
// fooObject is accessable here
const char* str = "hello";
fooObject.append(str, strlen(str));
output_test_stream output;
output << fooObject;
BOOST_CHECK( output.is_equal(str) );
}
g++ tells me that:
In function ‘T& operator<<(T&, const foo&)
[with T = boost::test_tools::output_test_stream]’:
error: invalid initialization of reference of type
‘boost::test_tools::output_test_stream&’ from expression of type
‘std::basic_ostream<char, std::char_traits<char> >’
What's going on?
I'm using Boost 1.34.1 on Ubuntu 8.04.
So I think I have an explanation, but no solution yet. output_test_stream implements its stream functionality by subclassing wrap_stringstream. The insertion-operator for this is a free function-template that looks like this:
template <typename CharT, typename T>
inline basic_wrap_stringstream<CharT>&
operator<<( basic_wrap_stringstream<CharT>& targ, T const& t )
{
targ.stream() << t;
return targ;
}
// ... further down in the same header
typedef basic_wrap_stringstream<char> wrap_stringstream;
Your operator is called with output_test_stream as the stream-type, and that makes this it's return-type. Your operator then calls the above operator, and just propagates the return value. The return value of the above operator however is a superclass of the returntype of your operator. When compiler tries to create the reference you want to return, it chokes, because it cannot initialize a reference to a subclass from a reference to a superclass, even if both refer to the same object. That make any sense?
You may know that already, but using output_test_stream as an std::ostream works:
class foo {
// [...]
friend
std::ostream& operator<< ( std::ostream &os, const foo &f );
};
std::ostream& operator<< ( std::ostream &os, const foo &f ) {
return os << f.data;
}
Is it a typo? You wrote
foo.append(str, strlen(str));
but foo is the name of the class and not an object.