С++ цепочка оператора << для использования std :: cout

Возможный дубликат:
std :: endl неизвестного типа при перегрузке оператора <<
Перегрузка оператора

В настоящее время я программирую класс журнала, но метод operator<< вызывает ошибку компилятора. Здесь свернутая версия класса, в файле "logger.h":

#include <iostream>
class Logger {
public:
    Logger() : m_file(std::cout) {}

    template <typename T>
    Logger &operator<<(const T &a) {
        m_file<<a;
        return *this;
    }

protected:
    std::ostream& m_file;
};

Он включен в мой main.cpp и отлично работает, когда я выводим строковый литерал:

log << "hi"; 

Однако следующее не будет компилироваться.

#include "logger.h"
int main() {
    Logger log;

    log << std::endl;
}

Компилятор g++ сообщает:

src/main.cpp: 5: ошибка: нет соответствия для "operator <<" в "log << std :: endl '

Ответ 1

Ваша проблема не в цепочке <<, один log << endl также вызовет проблему. Это потому, что std::endl - это функция шаблона:

template <class charT, class traits>
basic_ostream<charT,traits>& endl(basic_ostream<charT,traits>& os);

Одна из перегрузок operator<< в basic_ostream:

template <class charT, class traits = char_traits<charT> >
class basic_ostream : virtual public basic_ios<charT,traits> {
public:
    basic_ostream<charT,traits>& operator<<(
    basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&));
//...
};

Таким образом, параметры шаблона можно вывести, когда используется std::cout<<std::endl. Однако, когда левая сторона является class Logger, компилятор не может вывести параметры шаблона endl. Явно указать параметры шаблона, чтобы программа могла компилироваться и работать:

#include <iostream>
class Logger
{
public:
    std::ostream &m_file;
    Logger(std::ostream &o = std::cout):m_file(o){};

    template <typename T>
    Logger &operator<<(const T &a) {
        m_file<<a;
        return *this;
    }
};

int main()
{
    Logger log;
    log<<std::endl<char, std::char_traits<char> >;
    log<<"hi"<<" stackoverflow"<<std::endl<char, std::char_traits<char> >;
    return 0;
}

Или вы можете добавить новую перегрузку operator<< в class Logger чтобы позволить компилятору вывести параметры шаблона std::endl:

#include <iostream>
class Logger
{
public:
    std::ostream &m_file;
    Logger(std::ostream &o = std::cout):m_file(o){};

    template <typename T>
    Logger &operator<<(const T &a) {
        m_file<<a;
        return *this;
    }

    Logger &operator<<(std::ostream& (*pf) (std::ostream&)){
        m_file<<pf;
        return *this;
    }
};

int main()
{
    Logger log;
    log<<std::endl;
    log<<"hi"<<" stackoverflow"<<std::endl;
    return 0;
}

Кроме того, если вам не нужно сразу выводить вывод, вы можете использовать '\n' вместо endl.