C ++流作为重载运算符<<<<

时间:2010-05-10 14:29:58

标签: c++ operator-overloading stream endl

我正在尝试编写自己的日志记录类并将其用作流:

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;更改,有时它是指针的引用,有时看起来像双引用...

4 个答案:

答案 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<<