Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ chaining of the operator << for std::cout like usage [duplicate]

Possible Duplicate:
std::endl is of unknown type when overloading operator<<
Operator overloading

I'm currently programming a logger class, but the operator<< method causes a compiler error. Here's a minimized version of the class, in file "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;
};

It is included in my main.cpp and works perfecly when I output a string literal:

log << "hi"; 

However, the following won't compile.

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

    log << std::endl;
}

The g++ compiler reports:

src/main.cpp:5: error: no match for 'operator<<' in 'log << std::endl'

like image 670
Tuxer Avatar asked Dec 07 '11 13:12

Tuxer


1 Answers

Your problem is not about the chain of << , a single log << endl would also cause the problem. It is because std::endl is a template function:

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

One of the overload of operator<< in basic_ostream is:

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>&));
//...
};

So the template parameters can be deduced when std::cout<<std::endl is used. However, when the left side is the class Logger, the compile cannot deduce the template parameters of endl. Explicitly give the template parameters can let program compile and work:

#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;
}

Or you can add a new overload of operator<< in class Logger to let compiler deduce the template parameters of 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;
}

Also, if you don't need the output to be flushed immediately, you can use '\n' instead of endl.

like image 166
fefe Avatar answered Oct 28 '22 13:10

fefe