当重载operator <<时,std :: endl是未知的types
我重载了operator <<
template <Typename T> UIStream& operator<<(const T); UIStream my_stream; my_stream << 10 << " heads";
作品,但是:
my_stream << endl;
给汇编错误:
错误C2678:二进制'<<':找不到操作符findtypes为'UIStream'的左手操作数(或没有可接受的转换)
什么是使my_stream << endl
工作的工作?
std::endl
是一个函数, std::cout
通过实现operator<<
来使用与std::endl
具有相同签名的函数指针。
在那里,它调用函数,并转发返回值。
这是一个代码示例:
#include <iostream> struct MyStream { template <typename T> MyStream& operator<<(const T& x) { std::cout << x; return *this; } // function that takes a custom stream, and returns it typedef MyStream& (*MyStreamManipulator)(MyStream&); // take in a function with the custom signature MyStream& operator<<(MyStreamManipulator manip) { // call the function, and return it's value return manip(*this); } // define the custom endl for this stream. // note how it matches the `MyStreamManipulator` // function signature static MyStream& endl(MyStream& stream) { // print a new line std::cout << std::endl; // do other stuff with the stream // std::cout, for example, will flush the stream stream << "Called MyStream::endl!" << std::endl; return stream; } // this is the type of std::cout typedef std::basic_ostream<char, std::char_traits<char> > CoutType; // this is the function signature of std::endl typedef CoutType& (*StandardEndLine)(CoutType&); // define an operator<< to take in std::endl MyStream& operator<<(StandardEndLine manip) { // call the function, but we cannot return it's value manip(std::cout); return *this; } }; int main(void) { MyStream stream; stream << 10 << " faces."; stream << MyStream::endl; stream << std::endl; return 0; }
希望这可以让你更好地了解这些东西是如何工作的。
问题是std::endl
是一个函数模板,因为你的operator <<
是。 所以当你写:
my_stream << endl;
你会喜欢编译器推导运算符以及endl
的模板参数。 这是不可能的。
所以你必须编写额外的,非模板的operator <<
重载操作符。 他们的原型将如下所示:
UIStream& operator<<(UIStream& os, std::ostream& (*pf)(std::ostream&));
(还有另外两个,用std::ostream
std::basic_ios<char>
和std::ios_base
replacestd::ostream
,如果你想允许所有的操纵器,你也可以提供它们),它们的实现将非常类似于你的模板。 事实上,如此类似,你可以使用你的模板来实现这样的事情:
typedef std::ostream& (*ostream_manipulator)(std::ostream&); UIStream& operator<<(UIStream& os, ostream_manipulator pf) { return operator<< <ostream_manipulator> (os, pf); }
最后一点,经常写一个自定义的streambuf
往往是一个更好的方法来实现你正在使用的技术,试图实现。
看到这里更好的方式来扩展IOStreams。 (有点过时了,为VC 6量身打造,所以你必须拿一粒盐)
关键是要使函子工作(和endl,这两个输出“\ n”和冲洗是一个仿函数),你需要实现完整的ostream接口。
std
stream不是被devise为subclassed的,因为他们没有虚拟方法,所以我不认为你会得到太多的。 你可以尝试聚合一个std :: ostream来完成这项工作。
为了使endl
能够工作,你需要实现一个operator<<
的operator<<
,这个operator<<
指向的函数就像endl
这样的operator<<
是如何处理的
UStream& operator<<( UStream&, UStream& (*f)( UStream& ) );
要么
UStream& UStream::operator<<( UStream& (*f)( UStream& ) );
现在, std::endl
是一个函数,它接受并返回一个std :: basic_ostream的引用,这样就不会直接与你的stream进行工作,所以你需要创build自己的版本来调用std::endl
版本在你的聚合std::iostream
。
编辑:看起来像GMan的答案是更好的。 他得到std::endl
工作!
我这样做是为了解决我的问题,这里是我的代码的一部分:
template<typename T> CFileLogger &operator <<(const T value) { (*this).logFile << value; return *this; } CFileLogger &operator <<(std::ostream& (*os)(std::ostream&)) { (*this).logFile << os; return *this; }
Main.cpp的
int main(){ CFileLogger log(); log << "[WARNINGS] " << 10 << std::endl; log << "[ERRORS] " << 2 << std::endl; ... }
我在这里得到了参考http://www.cplusplus.com/forum/general/49590/
希望这可以帮助别人。
除了被接受的答案之外,在C ++ 11中,还可以重载operator<<
,
decltype(std::endl<char, std::char_traits<char>>)