在C++中,有一个名为cout
的标准库函数,它允许我将文本发送到控制台。我相信你知道这一点。
#include <iostream>
using std::cout;
cout << "Some Text " << 15 << " Other Text";
要在最后做换行符,我需要使用endl
.
cout << "Some Text " << 15 << " Other Text" << endl;
如何编写一个名为coutl
的函数,它的行为类似于cout
但也添加了 likebreak?我想使用与cout
相同的语法,尤其是<<
运算符。
coutl << "Some Text " << 15 << " Other Text"; // coutl should add a linebreak
通过创建一个在其析构函数中添加<< endl
的小代理对象:
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;
}
然后你需要一个函数,以便你得到一个临时的:
AddEndl wrap(std::ostream& os)
{
return AddEndl(os);
}
然后,这应该可以工作:
wrap(std::cout) << "Hello";
更新:
我移动了析构函数,该析构函数将std::endl
添加到std::shared_ptr<>
拥有的内部对象,以便该示例不再依赖于 Copy Elision。
仅使用在堆栈上创建的非临时对象是不可能的,并且具有完整的功能范围。对象怎么会知道这是对<< operator
的最后一个链式调用是什么?
你可以尝试这样的黑客
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";
}
另一个使用析构函数的类似黑客
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";
}
}
事实上的代码
cout << "Some Text " << 15 << " Other Text" << endl;
调用运算符函数
// (pseudo code)
std::ostream& operator<<(std::ostream, [type] obj);
每次使用几次<<
运算符。 要实现你想要的,你需要创建一个行为类似于std::ostream
的类,但"神奇地"知道何时发出对operator<<
的"最后一次"调用并附加换行符。恕我直言,如果没有另一个跟踪语句范围的对象,这是不可能的。
coutl << "Some Text " << 15 << " Other Text"; // coutl should add a linebreak
你的想法无法实现。实际上,cout << str1;
等效于返回 cout 本身引用的cout.operator<<(str1)
。因此,cout << a << b << c;
可以解析为((cout << a) << b) << c;
它不知道插入换行符的最后一次调用是什么时候。