Suppose that you have the following code:
#include <iostream>
template <typename T>
class Example
{
public:
Example() = default;
Example(const T &_first_ele, const T &_second_ele) : first_(_first_ele), second_(_second_ele) { }
friend std::ostream &operator<<(std::ostream &os, const Example &a)
{
return (os << a.first_ << " " << a.second_);
}
private:
T first_;
T second_;
};
int main()
{
Example example_(3.45, 24.6); // Example<double> till C++14
std::cout << example_ << "\n";
}
Is this the only way to overload the operator<<?
friend std::ostream &operator<<(std::ostream &os, const Example &a)
{
return (os << a.first_ << " " << a.second_);
}
In terms of performance, is it the best way to overload it or are there better options to do this implementation?
I believe that the comments have answered your question well enough. From a pure performance standpoint, there likely is no "better" way to overload the << operator for output streams because your function is likely not the bottleneck in the first place.
I will suggest that there is a "better" way to write the function itself that handles some corner cases.
Your << overload, as it exists now, will 'break' when trying to perform certain output formatting operations.
std::cout << std::setw(15) << std::left << example_ << "Fin\n";
This does not left align your entire Example output. Instead it only left aligns the first_ member. This is because you put your items in the stream one at a time. std::left will grab the next item to left align, which is only a part of your class output.
The easiest way is to build a string and then dump that string into your output stream. Something like this:
friend std::ostream &operator<<(std::ostream &os, const Example &a)
{
std::string tmp = std::to_string(a.first_) + " " + std::to_string(a.second_);
return (os << tmp);
}
It's worth noting a few things here. The first is that in this specific example, you will get trailing 0's because you don't get any control over how std::to_string() formats its values. This may mean writing type-specific conversion functions to do any trimming for you. You may also be able to use std::string_views (to gain back some efficiency (again, it likely doesn't matter as the function itself is probably still not your bottleneck)), but I have no experience with them.
By putting all of the object's information into the stream at once, that left-align will now align the full output of your object.
There is also the argument about friend vs. non-friend. If the necessary getters exist, I would argue that non-friend is the way to go. Friends are useful, but also break encapsulation since they are non-member functions with special access. This gets way into opinion territory, but I don't write simple getters unless I feel that they are necessary, and I don't count << overloads as necessary.
As I understand, the question poses two ambiguity points:
Whether you are specifically aiming at templated classes.
I will assume the answer is YES.
Whether there are better ways to overload the ostream operator<< (as compared to the friend-way), as posted in the title of the question (and assuming "better" refers to performance), or there are other ways, as posted in the body ("Is this the only way..."?)
I will assume the first, as it encompasses the second.
I conceive at least 3 ways to overload the ostream operator<<:
The friend-way, as you posted.
The non-friend-way, with auto return type.
The non-friend-way, with std::ostream return type.
They are exemplified at the bottom.
I ran several tests. From all those test (see below the code used for that), I concluded that:
Having compiled/linked in optimize mode (with -O3), and looping 10000 times each std::cout, all 3 methods provide essentially the same performance.
Having compiled/linked in debug mode, without looping
t1 ~ 2.5-3.5 * t2
t2 ~ 1.02-1.2 * t3
I.e., 1 is much slower than 2 and 3, which perform similarly.
I wouldn't know if these conclusions apply across systems.
I wouldn't know either if you might be seeing behavior closer to 1 (most likely), or 2 (under particular conditions).
Code to define the three methods to overload operator<<
(I have removed default constructors, as they are irrelevant here).
Method 1 (as in the OP):
template <typename T>
class Example
{
public:
Example(const T &_first_ele, const T &_second_ele) : first_(_first_ele), second_(_second_ele) { }
friend std::ostream &operator<<(std::ostream &os, const Example &a)
{
return (os << a.first_ << " " << a.second_);
}
private:
T first_;
T second_;
};
Method 2:
template <typename T>
class Example2
{
public:
Example2(const T &_first_ele, const T &_second_ele) : first_(_first_ele), second_(_second_ele) { }
void print(std::ostream &os) const
{
os << this->first_ << " " << this->second_;
return;
}
private:
T first_;
T second_;
};
template<typename T>
auto operator<<(std::ostream& os, const T& a) -> decltype(a.print(os), os)
{
a.print(os);
return os;
}
Method 3:
template <typename T>
class Example3
{
public:
Example3(const T &_first_ele, const T &_second_ele) : first_(_first_ele), second_(_second_ele) { }
void print(std::ostream &os) const
{
os << this->first_ << " " << this->second_;
return;
}
private:
T first_;
T second_;
};
// Note 1: If this function exists, the compiler makes it take precedence over auto... above
// If it does not exist, code compiles ok anyway and auto... above would be used
template <typename T>
std::ostream &operator<<(std::ostream &os, const Example3<T> &a)
{
a.print(os);
return os;
}
// Note 2: Explicit instantiation is not needed here.
//template std::ostream &operator<<(std::ostream &os, const Example3<double> &a);
//template std::ostream &operator<<(std::ostream &os, const Example3<int> &a);
Code used to test performance
(everything was placed in a single source file with
#include <iostream>
#include <chrono>
at the top):
int main()
{
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
const int nout = 10000;
Example example_(3.45, 24.6); // Example<double> till C++14
begin = std::chrono::steady_clock::now();
for (int i = 0 ; i < nout ; i++ )
std::cout << example_ << "\n";
end = std::chrono::steady_clock::now();
const double lapse1 = std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count();
std::cout << "Time difference = " << lapse1 << "[us]" << std::endl;
Example2 example2a_(3.5, 2.6); // Example2<double> till C++14
begin = std::chrono::steady_clock::now();
for (int i = 0 ; i < nout ; i++ )
std::cout << example2a_ << "\n";
end = std::chrono::steady_clock::now();
const double lapse2a = std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count();
std::cout << "Time difference = " << lapse2a << "[us]" << std::endl;
Example2 example2b_(3, 2); // Example2<double> till C++14
begin = std::chrono::steady_clock::now();
for (int i = 0 ; i < nout ; i++ )
std::cout << example2b_ << "\n";
end = std::chrono::steady_clock::now();
const double lapse2b = std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count();
std::cout << "Time difference = " << lapse2b << "[us]" << std::endl;
Example3 example3a_(3.4, 2.5); // Example3<double> till C++14
begin = std::chrono::steady_clock::now();
for (int i = 0 ; i < nout ; i++ )
std::cout << example3a_ << "\n";
end = std::chrono::steady_clock::now();
const double lapse3a = std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count();
std::cout << "Time difference = " << lapse3a << "[us]" << std::endl;
std::cout << "Time difference lapse1 = " << lapse1 << "[us]" << std::endl;
std::cout << "Time difference lapse2a = " << lapse2a << "[us]" << std::endl;
std::cout << "Time difference lapse2b = " << lapse2b << "[us]" << std::endl;
std::cout << "Time difference lapse3a = " << lapse3a << "[us]" << std::endl;
return 0;
}
It's the obvious way to implement it. It's also probably the most efficient. Use it.
The way you demonstrated in the question is the most basic way, which is also found in various C++ books. Personally I may not prefer in my production code, mainly because:
Have to write the boilerplate code for friend operator<< for each and every class.
When adding new class members, you may have to update the methods as well individually.
I would recommend following way since C++14:
Library
// Add `is_iterable` trait as defined in https://stackoverflow.com/a/53967057/514235
template<typename Derived>
struct ostream
{
static std::function<std::ostream&(std::ostream&, const Derived&)> s_fOstream;
static auto& Output (std::ostream& os, const char value[]) { return os << value; }
static auto& Output (std::ostream& os, const std::string& value) { return os << value; }
template<typename T>
static
std::enable_if_t<is_iterable<T>::value, std::ostream&>
Output (std::ostream& os, const T& collection)
{
os << "{";
for(const auto& value : collection)
os << value << ", ";
return os << "}";
}
template<typename T>
static
std::enable_if_t<not is_iterable<T>::value, std::ostream&>
Output (std::ostream& os, const T& value) { return os << value; }
template<typename T, typename... Args>
static
void Attach (const T& separator, const char names[], const Args&... args)
{
static auto ExecuteOnlyOneTime = s_fOstream =
[&separator, names, args...] (std::ostream& os, const Derived& derived) -> std::ostream&
{
os << "(" << names << ") =" << separator << "(" << separator;
int unused[] = { (Output(os, (derived.*args)) << separator, 0) ... }; (void) unused;
return os << ")";
};
}
friend std::ostream& operator<< (std::ostream& os, const Derived& derived)
{
return s_fOstream(os, derived);
}
};
template<typename Derived>
std::function<std::ostream&(std::ostream&, const Derived&)> ostream<Derived>::s_fOstream;
Usage
Inherit the above class for those classes for whom you want the operator<< facility. Automatically friend will get included into those class's definition via base ostream. So no extra work. e.g.
class MyClass : public ostream<MyClass> {...};
Preferably in their constructors, you may Attach() the member variables which are to be printed. e.g.
// Use better displaying with `NAMED` macro
// Note that, content of `Attach()` will effectively execute only once per class
MyClass () { MyClass::Attach("\n----\n", &MyClass::x, &MyClass::y); }
Example
From what you shared,
#include"Util_ostream.hpp"
template<typename T>
class Example : public ostream<Example<T>> // .... change 1
{
public:
Example(const T &_first_ele, const T &_second_ele) : first_(_first_ele), second_(_second_ele)
{
Example::Attach(" ", &Example::first_, &Example::second_); // .... change 2
}
private:
T first_;
T second_;
};
Demo
This approach has a pointer access per every print of the variable instead of direct. This negligible indirection should never be a bottle-neck in a code from the performance perspective.
Demo is slight more complex for practical purpose.
Requirements
The intention here is to improve readability and uniformity of printing the variables
Every printable class should have their separate ostream<T> regardless of inheritance
An object should have operator<< defined or ostream<T> inherited to be able to compile
Facilities
This is now shaping up as a good library component. Below are add-on facilities, I have added so far.
Using ATTACH() macro, we can also print variable in certain way; Variable printing can always be customised as per need by modifying the library code
If the base class is printable, then we can simply pass a typecasted this; Rest will be taken care
Containers with std::begin/end compatibility are now supported, which includes vector as well as map
The code shown in the beginning is shorter for the quick understanding purpose. Those who are further interested may click on the demo link above.
Related
I have written an example type erasure program, but I noticed something that seemed strange. The code compiles - and I believe it shouldn't. More likely, it does something that I don't understand which enables it to compile.
Here is a MWE.
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class Object
{
public:
template<typename T>
Object(T value)
: p_data(std::make_unique<Model<T>>(std::move(value)))
{
}
Object(const Object& object)
: p_data(object.p_data->copy())
{
}
Object(Object&& other) noexcept = default;
Object& operator=(const Object& object)
{
Object tmp(object);
*this = std::move(tmp);
return *this;
}
Object& operator=(Object&& object) noexcept = default;
friend std::ostream& operator<<(std::ostream&, const Object&);
private:
struct Concept;
std::unique_ptr<Concept> p_data;
struct Concept
{
virtual
~Concept() = default;
virtual
std::unique_ptr<Concept> copy() const = 0;
virtual
void draw_internal(std::ostream&) const = 0;
};
template<typename T>
struct Model : public Concept
{
Model(T value)
: data(std::move(value))
{
}
std::unique_ptr<Concept> copy() const override
{
return std::make_unique<Model<T>>(data);
}
void draw_internal(std::ostream& os) const override
{
std::cout << "Model<T>::draw_internal(std::ostream& os)" << std::endl;
os << data;
}
T data;
};
};
// This enables us to do
// std::cout << Object
// We forward the call to unique_ptr<Concept>::draw_internal using virtual function
// dispatch
std::ostream& operator<<(std::ostream& os, const Object& object)
{
std::cout << "operator<<(std::ostream& os, const Object& object" << std::endl;
object.p_data->draw_internal(os);
return os;
}
int main()
{
std::vector<Object> document;
document.push_back(0);
document.push_back(std::string("Hello World"));
std::cout << "Drawing now!" << std::endl;
std::cout << document << std::endl;
std::cout << std::endl;
return 0;
}
Actually this is a broken example—at runtime the code enters an infinite loop. No doubt for reasons related to the fact that it compiles when it (maybe) shouldn't.
Here's why I think it shouldn't compile:
There is no operator<< defined for the type std::vector<Object>.
That said, I suspect this compiles, because the compiler is able to generate a compatible operator from something within this code. I just don't understand exactly how it has done this. My guess would be there is an implicit conversion from std::vector<Object> to Object<T> with T=std::vector<Object>? But this is really a guess.
At runtime there is an infinite loop caused by operator<< calling itself. I don't understand exactly why this happens either.
Interestingly, here are two things which do not compile:
std::vector<int> a;
std::cout << a << std::endl;
std::vector<std::string> b;
std::cout << b << std::endl;
So the compiler clearly can't generate operator<< for any type. This makes me think my guess about what is happening is wrong.
It was compiled with GCC 12 (Mingw-w64) on Windows 10.
Godbolt
You could have stripped your example down bit by bit to get to a MWE like this:
#include <iostream>
#include <vector>
struct Object {
template<typename T> Object(T) {} // #1
friend std::ostream& operator<<(std::ostream&, const Object&); // #2
};
int main()
{
std::vector<Object> document;
std::cout << document << std::endl;
}
I truly just removed pieces as long as the program would compile, stopping only when I couldn't reasonably remove anything else.
Once got to this point it's easy to experiment and, in this specific situation, find out that commenting either #1 or #2 makes the program fail to compile.
The step is short to connect that to the solution to the question.
By they way, the suggestion in one of the comments to the question of using explicit really pays off.
There is no operator<< defined for the type std::vector.
Nearly any type is convertible to Object thanks to the constructor template here:
template<typename T>
Object(T value)
: p_data(std::make_unique<Model<T>>(std::move(value)))
{
}
Thus this operator overload:
std::ostream& operator<<(std::ostream& os, const Object& object)
Can take almost any argument
I believe I have figured it out. Someone may correct me if this is wrong.
Starting from
cout << document
this is, in terms of the types involved
cout << vector<Object<T>>
This is implicitly converted to
cout << Object<vector<Object<T>>>
I'll just add this line, which we will refer back to later. Since cout is a type of ostream, we more precisely have this:
ostream << Object<vector<Object<T>>> // call this (A)
Looking at the function call for operator<<(ostream&, Object<T>& object) we can see that it does this:
[ operator<<(ostream&, Object<T>& object) ] :
object.p_data->draw_internal(...)
Converting that to the type, we have this:
object.[unique_ptr<W>]->draw_internal(...)
with W = Model<T>, T = vector<Object<U>>.
So this is a function call to
Model<T>::draw_internal(ostream& os)
and draw_internal does this:
[ Model<T>::draw_internal(ostream& os) ] :
os << data
where data is of type T = vector<Object<U>>. Therefore it is a function call like this:
os << vector<Object<U>>
Because of the implicit conversion we saw previously, the compiler actually converts this into
os << Object<vector<Object<U>>
In other words, it does this:
os << Object(data) // instead of just os << data
and hence we have a loop. operator<< is calling itself via draw_internal. See (A) above.
I am feeling a bit confused about how to instantiate this template. I know it is gonna be easier to simply use friend membership to realize what I want, but what if I force to do in this way? I just wanna figure it out. (And btw, I know this template seems meaningless), I just want to make it compile.
#include <iostream>
template <typename T>
inline std::ostream& operator<< (std::ostream& os, const T& date)
{
os << date.getD() << " " << date.getM() << " " << date.getY() << "\n";
return os;
}
class Date
{
private:
int dd, mm, yy;
public:
Date(int d, int m, int y) : dd(d), mm(m), yy(y) {}
int getD() const;
int getM() const;
int getY() const;
};
int Date::getD() const { return dd; }
int Date::getM() const { return mm; }
int Date::getY() const { return yy; }
int main(int argc, char const *argv[])
{
Date dat(1, 2, 2003);
std::cout << <Date> dat;
return 0;
}
Two issues:
You're declaring operator<< as template that could accept any types; which would lead to ambiguity issue with std::operator<<.
You can't specify template argument explicitly when calling the operator in operator style. (You can do it in ugly function style like operator<< <Date>(std::cout, dat);) Actually you don't need to specify it, the template parameter could be deduced fine here.
You can change the code to
std::ostream& operator<< (std::ostream& os, const Date& date) {
os << date.getD() << " " << date.getM() << " " << date.getY() <<"\n";
return os;
}
then
Date dat(1,2,2003);
std::cout << dat;
LIVE
but what if I force to do in this way?
As others mentioned, you do not need a template here. But if you insist to do it by templates, you can apply SFINAE to the templated overload of operator<<.
(See live here)
#include <type_traits> // std::enable_if, std::is_same
template <typename T>
auto operator<< (std::ostream& os, const T& date)
-> std::enable_if_t<std::is_same_v<Date, T>, std::ostream&>
{
os << date.getD() << " " << date.getM() << " " << date.getY() << "\n";
return os;
}
This will be done automatically by the compiler. Simply do
int main(int argc, char const *argv[])
{
Date dat(1,2,2003);
std::cout << dat;
return 0;
}
This is done with ADL (Argument-dependent lookup).
I just came across the problem of combining custom output operators with io-manipulators. Maybe my expectations are completely off, but if
std::cout << foo() << "\n";
prints
00
then I would expect
std::cout << std::left << std::setw(20) << foo() << "!\n"
to print
00 !
but given this implementation
#include <iostream>
#include <iomanip>
struct foo { int a,b; };
std::ostream& operator<<(std::ostream& out, const foo& f) {
out << f.a << f.b;
return out;
}
int main() {
std::cout << foo() << "\n";
std::cout << std::left << std::setw(20) << foo() << "!";
}
what is printed on the screen is
00
0 0!
I see basically two options: A) My expectations are just wrong. B) I use this implementation instead:
std::ostream& operator<<(std::ostream& out, const foo& f) {
std::stringstream ss;
ss << f.a << f.b;
out << ss.str();
return out;
}
However, this seems like quite some overhead considering that most of the time no io manipulators are used.
What is the idiomatic way of treating io-manipulators "correctly" in custom output operators?
I'm afraid there is no easy answer. Your solution is idiomatic if you only need to handle std::setw and std::left, but, for other manipulations, you have to decide the behavior of your formatter.
Imagine, for example, if your struct had floats instead of ints:
struct foo { float a,b; };
Then, your user tries to do this:
const long double pi = std::acos(-1.L);
std::cout << std::setprecision(10) << foo{0.0f, pi} << "!\n"
This is when you have to decide: Do you want to honor the precision property of the output stream, or do you want to ignore it? Your current implementation would ignore it, since it does the actual conversion in another stream.
To honor the precision property, you would have to copy it:
std::ostream& operator<<(std::ostream& out, const foo& f) {
std::stringstream ss;
ss.precision(out.precision());
ss << f.a << f.b;
out << ss.str();
return out;
}
For your case of integers, you also have to consider if you will honor std::setbase or not.
The same reasoning will have to be applied for the other manipulators, such as std::setfill, for example.
Not necessarily idiomatic, but one possible appraoch is this:
struct foo {
int a,b;
std::string toString() {
std::stringstream ss;
ss << a << b;
return ss.str();
}
};
std::ostream& operator<<(std::ostream& out, const foo& f) {
out << a << b;
return out;
};
Now the caller may choose whether output should be as a whole or not:
std::cout << std::left << std::setw(20) << foo().toString() << "!"; // output as expected
std::cout << foo(); // output as expected
// and no unnecessary overhead
One might also argue that output is already slow, so a bit of additional overhead does not hurt and simply implement the output operator in terms of the stringify method:
std::ostream& operator<<(std::ostream& out, const foo& f) {
out << f.toString();
return out;
}
This also fixed the minor ugliness of the first approach which basically implements the same thing twice with almost identical code.
If I want to overload the << operator to use cout on a class, it should look like this:
template <typename coutT>
friend ostream& operator << (ostream &, const vector3D<coutT>&);
inside the class, and
template <typename coutT>
ostream& operator << (ostream & os,const vector3D<coutT>& v)
{
os << "x: " << v.x<< " y: " << v.y << " z: " << v.z;
return os;
}
on the outside. Please take note of the const at the second operand.
This sample of code works just fine. Now to the problem.
If I were to write the overload function using the getters for the fields, instead of addressing them directly (since operator<< is a friend), my compiler would throw an error:
template <typename coutT>
ostream& operator << (ostream & os,const vector3D<coutT>& v)
{
os << "x: " << v.getX() << " y: " << v.getY() << " z: " << v.getZ();
return os;
}
The error:
(VisualStudio2012) errorC2662: "this-pointer cannot be converted from "const vector3D" in "vector3D&""
An important note is that deleting the "const" at the second operand so that it's like
ostream& operator << (ostream & os,vector3D<coutT>& v){...}
ended compiler errors, but since I don't want to change v, it should really be a const.
I should also mention that I think it may have to do with method calls in general, but I'm not sure.
edit:
So it is solved, declaring functions as const sticks to const-correctness.
The error message explains it in the way that it cannot cast the const type to a non-const one.
btw.: I'm actually impressed about the quick responses.
The getter function should be declared const if you want to use it that way.
For example
int getValue() const {
return x;
}
Complete example:
#include <iostream>
#include <vector>
using namespace std;
class Foo {
int x;
public:
Foo(int a) : x(a) {
}
int getValue() const {
return x;
}
friend ostream & operator<<(ostream & out, const Foo & foo) {
return out << foo.getValue();
}
};
int main() {
vector<Foo> foo_vec = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for (vector<Foo>::iterator it = foo_vec.begin(); it != foo_vec.end(); it++) {
cout << *it << ", ";
}
return 0;
}
Your problem is that you didn't mark the get functions const:
They need to look like this:
double getX() const;
You need to make the accessor functions const:
struct V
{
int getX() const { /* ... */ }
^^^^^
};
Only const member functions can be invoked on constant object values. In turn, const member functions cannot mutate the object. Thus const-correctness guarantees that a constant value cannot be mutated by invoking any of its member functions.
I want to write a function that outputs something to a ostream that's passed in, and return the stream, like this:
std::ostream& MyPrint(int val, std::ostream* out) {
*out << val;
return *out;
}
int main(int argc, char** argv){
std::cout << "Value: " << MyPrint(12, &std::cout) << std::endl;
return 0;
}
It would be convenient to print the value like this and embed the function call in the output operator chain, like I did in main().
It doesn't work, however, and prints this:
$ ./a.out
12Value: 0x6013a8
The desired output would be this:
Value: 12
How can I fix this? Do I have to define an operator<< instead?
UPDATE: Clarified what the desired output would be.
UPDATE2: Some people didn't understand why I would print a number like that, using a function instead of printing it directly. This is a simplified example, and in reality the function prints a complex object rather than an int.
You can't fix the function. Nothing in the spec requires a compiler to evaluate a function call in an expression in any particular order with respect to some unrelated operator in the same expression. So without changing the calling code, you can't make MyPrint() evaluate after std::cout << "Value: "
Left-to-right order is mandated for expressions consisting of multiple consecutive << operators, so that will work. The point of operator<< returning the stream is that when operators are chained, the LHS of each one is supplied by the evaluation of the operator to its left.
You can't achieve the same thing with free function calls because they don't have a LHS. MyPrint() returns an object equal to std::cout, and so does std::cout << "Value: ", so you're effectively doing std::cout << std::cout, which is printing that hex value.
Since the desired output is:
Value: 12
the "right" thing to do is indeed to override operator<<. This frequently means you need to either make it a friend, or do this:
class WhateverItIsYouReallyWantToPrint {
public:
void print(ostream &out) const {
// do whatever
}
};
ostream &operator<<(ostream &out, const WhateverItIsYouReallyWantToPrint &obj) {
obj.print(out);
}
If overriding operator<< for your class isn't appropriate, for example because there are multiple formats that you might want to print, and you want to write a different function for each one, then you should either give up on the idea of operator chaining and just call the function, or else write multiple classes that take your object as a constructor parameter, each with different operator overloads.
You want to make MyPrint a class with friend operator<<:
class MyPrint
{
public:
MyPrint(int val) : val_(val) {}
friend std::ostream& operator<<(std::ostream& os, const MyPrint& mp)
{
os << mp.val_;
return os;
}
private:
int val_;
};
int main(int argc, char** argv)
{
std::cout << "Value: " << MyPrint(12) << std::endl;
return 0;
}
This method requires you to insert the MyPrint object into the stream of your choice. If you REALLY need the ability to change which stream is active, you can do this:
class MyPrint
{
public:
MyPrint(int val, std::ostream& os) : val_(val), os_(os) {}
friend std::ostream& operator<<(std::ostream& dummy, const MyPrint& mp)
{
mp.os_ << mp.val_;
return os_;
}
private:
int val_;
std::ostream& os_
};
int main(int argc, char** argv)
{
std::cout << "Value: " << MyPrint(12, std::cout) << std::endl;
return 0;
}
You have two options. The first, using what you already have is:
std::cout << "Value: ";
MyPrint(12, &std::cout);
std::cout << std::endl;
The other, which is more C++-like, is to replace MyPrint() with the appropriate std::ostream& operator<<. There's already one for int, so I'll do one just a tad more complex:
#include <iostream>
struct X {
int y;
};
// I'm not bothering passing X as a reference, because it's a
// small object
std::ostream& operator<<(std::ostream& os, const X x)
{
return os << x.y;
}
int main()
{
X x;
x.y = 5;
std::cout << x << std::endl;
}
There's no way to do what you're expecting there because of the order the functions are evaluated in.
Is there any particular reason you need to write directly to the ostream like that? If not, just have MyPrint return a string. If you want to use a stream inside MyPrint to generate the output, just use a strstream and return the result.
First, there is no reason not to pass in the ostream by reference rather than by a pointer:
std::ostream& MyPrint(int val, std::ostream& out) {
out << val;
return out;
}
If you really don't want to use std::ostream& operator<<(std::ostream& os, TYPE), you can do this:
int main(int argc, char** argv){
std::cout << "Value: ";
MyPrint(12, std::cout) << std::endl;
return 0;
}
After changing the pointer to a reference, you can do this:
#include <iostream>
std::ostream& MyPrint(int val, std::ostream& out) {
out << val;
return out;
}
int main(int, char**) {
MyPrint(11, std::cout << "Value: ") << std::endl;
return 0;
}
The syntax for MyPrint is essentially that of an unrolled operator<< but with an extra argument.
In your case the answer is obviously:
std::cout << "Value: " << 12 << std::endl;
If that isn't good enough, please explain what output you want to see.