问题
In C++ there is a standard library function called cout
, which lets me send text to the console. I am sure you know that.
#include <iostream>
using std::cout;
cout << "Some Text " << 15 << " Other Text";
To do a linebreak at the end, I need to use endl
.
cout << "Some Text " << 15 << " Other Text" << endl;
How can I write a function named coutl
which behaves like cout
but also adds a likebreak? I want to use the same syntax that cout
uses, especially the <<
operator.
coutl << "Some Text " << 15 << " Other Text"; // coutl should add a linebreak
回答1:
By creating a little proxy object which adds << endl
in its destructor:
class AddEndl
{
public:
AddEndl(std::ostream& os) : _holder(new Holder(os)) {}
template <class T>
friend std::ostream& operator<< (const AddEndl& l, const T& t)
{
return (l._holder->_os) << t;
}
private:
struct Holder {
Holder (std::ostream& os) : _os(os) {}
~Holder () { _os << std::endl; }
std::ostream& _os;
};
mutable std::shared_ptr<Holder> _holder;
}
Then you need a function so that you will get a temporary:
AddEndl wrap(std::ostream& os)
{
return AddEndl(os);
}
This should then work:
wrap(std::cout) << "Hello";
UPDATE:
I move the destructor which adds a std::endl
to an inner object owned by a std::shared_ptr<>
so that the example doesn't depend on Copy Elision anymore.
回答2:
Not possible with just a non-temp object created on the stack & which has full function scope. How will the object ever know what this is the last of the chained calls to the << operator
?
You can try hacks like these
class coutl
{
public:
~coutl()
{
cout<<endl;
}
template<class T>
coutl &operator<<(const T &x)
{
cout<<x;
return *this;
}
};
int main()
{
coutl()<<"Hello"<<10<<"World";
coutl()<<"Hello"<<20<<"World";
}
Another similar hack using the destructor
class myostream
{
public:
~myostream()
{
cout<<endl;
}
template<class T>
myostream &operator<<(const T &x)
{
cout<<x;
return *this;
}
};
int main()
{
{
myostream coutl;
coutl<<"Hello"<<10<<"World";
}
{
myostream coutl;
coutl<<"Hello"<<10<<"World";
}
}
回答3:
In fact the code
cout << "Some Text " << 15 << " Other Text" << endl;
calls the operator function(s)
// (pseudo code)
std::ostream& operator<<(std::ostream, [type] obj);
several times for each use of the <<
operators.
To achieve what you want you would need to create a class that behaves like std::ostream
, but 'magically' knows when the 'last' call to operator<<
is issued and appends a linebreak. That's not possible IMHO without another object that keeps track of the statements scope.
回答4:
coutl << "Some Text " << 15 << " Other Text"; // coutl should add a linebreak
Your idea can't be realize. In fact, cout << str1;
is equivalent to cout.operator<<(str1)
which returns a reference of cout itself. So cout << a << b << c;
can be resolvd to ((cout << a) << b) << c;
It doesn't know when is the last call to insert an linebreak.
来源:https://stackoverflow.com/questions/12987860/write-a-simple-function-that-works-like-stdcout-but-adds-a-line-break-at-the