问题 C ++链接运算符


可能重复:
当重载operator <<时,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:错误:'log << std :: endl'中'operator <<'不匹配


2185
2017-12-07 13:15


起源



答案:


你的问题不在于链条 << ,一个 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


13
2017-12-07 13:40



“此外,您可以使用'\ n'代替 endl“如果OP希望确保输出缓冲区被刷新,那就不行了 最近了解到。 - Some programmer dude
是的,我会把它添加到我的答案中。 - fefe
谢谢,它有效:) - Tuxer


答案:


你的问题不在于链条 << ,一个 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


13
2017-12-07 13:40



“此外,您可以使用'\ n'代替 endl“如果OP希望确保输出缓冲区被刷新,那就不行了 最近了解到。 - Some programmer dude
是的,我会把它添加到我的答案中。 - fefe
谢谢,它有效:) - Tuxer


该错误是由 std::endl 这是一个功能。参考:

当重载operator <<时,std :: endl是未知类型


0
2017-12-07 13:42



std::cout 是一个功能? - jalf
我想埃里克想说的 std::endl 是一个功能。 - Frédéric Hamidi
我想你的意思是“std::endl 是一个功能模板“? - Mike Seymour
@Mike,好吧, std::endl 不是模板本身。它接受并返回一个模板化的类,是的,但它只是一个成员函数。它的声明看起来像 template<class charT, class traits> basic_ostream<charT, traits>& endl(basic_ostream<charT, traits>& os);。 - Frédéric Hamidi
@jalf,只是纠正措辞,我的意思是“std :: endl”;) - Eric Z