我正在尝试编写自己的日志记录类并将其用作流:
logger L;
L << "whatever" << std::endl;
这是我开始使用的代码:
#include <iostream>
using namespace std;
class logger{
public:
template <typename T>
friend logger& operator <<(logger& log, const T& value);
};
template <typename T>
logger& operator <<(logger& log, T const & value) {
// Here I'd output the values to a file and stdout, etc.
cout << value;
return log;
}
int main(int argc, char *argv[])
{
logger L;
L << "hello" << '\n' ; // This works
L << "bye" << "alo" << endl; // This doesn't work
return 0;
}
但是我在尝试编译时遇到错误,说没有运算符的定义&lt;&lt; (当使用std :: endl时):
pruebaLog.cpp:31: error: no match for ‘operator<<’ in ‘operator<< [with T = char [4]](((logger&)((logger*)operator<< [with T = char [4]](((logger&)(& L)), ((const char (&)[4])"bye")))), ((const char (&)[4])"alo")) << std::endl’
所以,我一直在尝试重载运算符&lt;&lt;接受这种流,但它让我发疯。我不知道怎么做。例如,我一直在ostream头文件中定义std :: endl,并用这个头写了一个函数:
logger& operator <<(logger& log, const basic_ostream<char,char_traits<char> >& (*s)(basic_ostream<char,char_traits<char> >&))
但没有运气。我尝试使用模板而不是直接使用char,并尝试使用“const ostream&amp; os”,并且没有尝试。
另一件令我烦恼的事情是,在错误输出中,运算符的第一个参数&lt;&lt;更改,有时它是指针的引用,有时看起来像双引用...
答案 0 :(得分:9)
endl
是一个奇怪的野兽。它不是一个恒定的值。事实上,在所有事情上,它都是一种功能。您需要一个特殊的覆盖来处理endl
:
logger& operator<< (logger& log, ostream& (*pf) (ostream&))
{
cout << pf;
return log;
}
这接受插入一个带ostream
引用并返回ostream
引用的函数。那就是endl
。
编辑:回应FranticPedantic有趣的问题“为什么编译器不能自动推断出这个?”。原因是如果你深入研究,endl
实际上本身就是一个模板函数。它被定义为:
template <class charT, class traits>
basic_ostream<charT,traits>& endl ( basic_ostream<charT,traits>& os );
也就是说,它可以采用任何类型的ostream
作为其输入和输出。所以问题不在于编译器不能推断出T const &
可能是一个函数指针,而是它无法弄清楚你打算通过哪个 endl
在。问题中提出的operator<<
的模板化版本将接受指向任何函数的指针作为其第二个参数,但同时,endl
模板表示无限一组潜在的函数,所以编译器在那里无能为力。
提供operator<<
的特殊重载,其第二个参数与endl
模板的特定实例匹配,允许调用解析。
答案 1 :(得分:5)
endl
是一个IO操纵器,它是一个仿函数,它通过引用接受流,对它执行一些操作,并通过引用返回该流。 cout << endl
相当于cout << '\n' << flush
,其中flush
是一个刷新输出缓冲区的操纵器。
在你的课堂上,你只需要为这个操作符写一个重载:
logger& operator<<(logger&(*function)(logger&)) {
return function(*this);
}
其中logger&(*)(logger&)
是接受并通过引用返回logger
的函数的类型。要编写自己的操纵器,只需编写一个与该签名匹配的函数,并让它在流上执行一些操作:
logger& newline(logger& L) {
return L << '\n';
}
答案 2 :(得分:0)
在C ++中,流缓冲区封装了底层的I / O机制。流本身只将转换封装到字符串和I / O方向。
因此,您应该使用其中一个预定义的流类,而不是自己创建。如果你有一个新的目标,你希望你的I / O去(如系统日志),你应该创建的是你自己的流缓冲区(从std::streambuf
派生)。
答案 3 :(得分:0)
我认为问题是您的流不会超载operator<<
以接受与std::endl
具有相同类型的函数,如此答案中所示:std::endl is of unknown type when overloading operator<<