重载operator <<时,C++流作为参数

Jos*_*ino 10 c++ operator-overloading stream endl

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

logger L;
L << "whatever" << std::endl;
Run Code Online (Sandbox Code Playgroud)

这是我开始使用的代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)

但是我在尝试编译时遇到错误,说没有operator <<的定义(当使用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’
Run Code Online (Sandbox Code Playgroud)

所以,我一直在尝试重载operator <<来接受这种流,但这让我很生气.我不知道怎么做.例如,我一直在ostream头文件中定义std :: endl,并用这个头写了一个函数:

logger& operator <<(logger& log, const basic_ostream<char,char_traits<char> >& (*s)(basic_ostream<char,char_traits<char> >&))
Run Code Online (Sandbox Code Playgroud)

但没有运气.我尝试使用模板而不是直接使用char,并尝试使用"const ostream&os",并没有尝试.

让我烦恼的另一件事是,在错误输出中,operator <<的第一个参数发生了变化,有时候它是对指针的引用,有时看起来像是双引用...

Tyl*_*nry 9

endl是一个奇怪的野兽.它不是一个恒定的值.事实上,在所有事情上,它都是一种功能.您需要一个特殊的覆盖来处理以下应用程序endl:

logger& operator<< (logger& log, ostream& (*pf) (ostream&))
{
  cout << pf;
  return log;
}
Run Code Online (Sandbox Code Playgroud)

这接受插入一个带ostream引用并返回ostream引用的函数.那是什么endl.

编辑:回应FranticPedantic有趣的问题"为什么编译器不能自动推断出这个?".原因是,如果你深入研究,endl实际上它本身就是一个模板函数.它被定义为:

template <class charT, class traits>
  basic_ostream<charT,traits>& endl ( basic_ostream<charT,traits>& os );
Run Code Online (Sandbox Code Playgroud)

也就是说,它可以ostream作为其输入和输出.所以,问题不在于编译器不能推断,T const &可能是一个函数指针,但它无法找出哪个 endl你的意思是传递作者的模板版本operator<<的问题,提出将接受一个指向任何功能作为它的第二个参数,但同时,endl模板代表了一组无限的潜在函数,因此编译器无法在那里做任何有意义的事情.

提供operator<<其第二个参数的特殊重载与模板的特定实例化匹配endl允许调用解析.


Jon*_*rdy 5

endl是一个IO操纵器,它是一个仿函数,通过引用接受流,对它执行一些操作,并通过引用返回该流.cout << endl相当于cout << '\n' << flush,哪里flush是一个刷新输出缓冲区的操纵器.

在您的课程中,您只需要为此运算符编写重载:

logger& operator<<(logger&(*function)(logger&)) {
    return function(*this);
}
Run Code Online (Sandbox Code Playgroud)

logger&(*)(logger&)函数的类型在哪里接受并logger通过引用返回.要编写自己的操纵器,只需编写一个与该签名匹配的函数,并让它在流上执行一些操作:

logger& newline(logger& L) {
    return L << '\n';
}
Run Code Online (Sandbox Code Playgroud)