重载运算符<<时std :: endl类型未知

我重载了运算符<<

template <Typename T>
UIStream& operator<<(const T);

UIStream my_stream;
my_stream << 10 << " heads";

可以,但是:

my_stream << endl;

给出编译错误:

错误C2678:二进制'<<':未找到采用'UIStream'类型的左操作数的运算符(或者没有可接受的转换)

使my_stream << endl正常工作的工作是什么?

Kazoom asked 2019-11-07T12:59:23Z
6个解决方案
80 votes

std::endl是一个函数,并且std::cout通过实现operator<<来使用具有与std::endl相同签名的函数指针来利用它。

在那里,它调用函数,并转发返回值。

这是一个代码示例:

#include <iostream>

struct MyStream
{
    template <typename T>
    MyStream& operator<<(const T& x)
    {
        std::cout << x;

        return *this;
    }


    // function that takes a custom stream, and returns it
    typedef MyStream& (*MyStreamManipulator)(MyStream&);

    // take in a function with the custom signature
    MyStream& operator<<(MyStreamManipulator manip)
    {
        // call the function, and return it's value
        return manip(*this);
    }

    // define the custom endl for this stream.
    // note how it matches the `MyStreamManipulator`
    // function signature
    static MyStream& endl(MyStream& stream)
    {
        // print a new line
        std::cout << std::endl;

        // do other stuff with the stream
        // std::cout, for example, will flush the stream
        stream << "Called MyStream::endl!" << std::endl;

        return stream;
    }

    // this is the type of std::cout
    typedef std::basic_ostream<char, std::char_traits<char> > CoutType;

    // this is the function signature of std::endl
    typedef CoutType& (*StandardEndLine)(CoutType&);

    // define an operator<< to take in std::endl
    MyStream& operator<<(StandardEndLine manip)
    {
        // call the function, but we cannot return it's value
        manip(std::cout);

        return *this;
    }
};

int main(void)
{
    MyStream stream;

    stream << 10 << " faces.";
    stream << MyStream::endl;
    stream << std::endl;

    return 0;
}

希望这可以使您更好地了解这些方法的工作原理。

GManNickG answered 2019-11-07T12:59:58Z
36 votes

问题是streambuf是一个功能模板,因为您的操作员是std::basic_ios<char>是。 所以当你写:

my_stream << endl;

您将希望编译器为运算符推导模板参数以及streambuf。这是不可能的。

因此,您必须将运算符streambuf的其他非模板重载编写为与机械手一起工作。 他们的原型看起来像:

UIStream& operator<<(UIStream& os, std::ostream& (*pf)(std::ostream&));

(还有另外两个,用std::basic_ios<char>替换了streambufstd::ios_base,如果要允许所有机械手)及其实现将与以下一种非常相似您的模板。 实际上,如此相似,您可以将模板用于像这样的实现:

typedef std::ostream& (*ostream_manipulator)(std::ostream&);
UIStream& operator<<(UIStream& os, ostream_manipulator pf)
{
   return operator<< <ostream_manipulator> (os, pf);
}

最后的注释,通常写一个自定义的streambuf,通常是一种更好的方法实现您尝试使用的技术。

AProgrammer answered 2019-11-07T13:00:52Z
7 votes

我这样做是为了解决我的问题,这是我的代码的一部分:

    template<typename T> 
    CFileLogger &operator <<(const T value)
    {
        (*this).logFile << value;
        return *this;
    }
    CFileLogger &operator <<(std::ostream& (*os)(std::ostream&))
    {
        (*this).logFile << os;
        return *this;
    }

Main.cpp

int main(){

    CFileLogger log();    
    log << "[WARNINGS] " << 10 << std::endl;
    log << "[ERRORS] " << 2 << std::endl;
    ...
}

我在这里有参考[http://www.cplusplus.com/forum/general/49590/]

希望这可以帮助某人。

Lucas Casagrande answered 2019-11-07T13:01:38Z
4 votes

有关扩展IOStream的更好方法,请参见此处。 (有些过时了,并且是为VC 6量身定制的,因此您必须带着一点盐来拿它)

关键是要使函子(和endl都输出“ \ n”和flushes是函子)起作用,您需要实现完整的ostream接口。

EFraim answered 2019-11-07T13:02:15Z
3 votes

std::endl流没有子类,因为它们没有虚拟方法,因此我认为您对此不会感到过分。 您可以尝试聚合std :: ostream来完成工作。

为了使std::endl工作,您需要实现std::endl的版本,该版本采用指向功能的指针,因为这就是处理诸如std::iostream之类的操纵器的方式。

UStream& operator<<( UStream&, UStream& (*f)( UStream& ) );

要么

UStream& UStream::operator<<( UStream& (*f)( UStream& ) );

现在std::endl是一个函数,该函数接受并返回对std :: basic_ostream的引用,因此该函数将无法直接与您的流一起使用,因此您需要创建自己的版本,并在汇总的std::iostream中调用std::endl版本。

编辑:看起来像GMan的答案更好。 他也得到了std::endl的工作!

Troubadour answered 2019-11-07T13:03:07Z
1 votes

除了可接受的答案,使用C ++ 11还可以为以下类型重载operator<<

decltype(std::endl<char, std::char_traits<char>>)
AlwaysLearning answered 2019-11-07T13:03:36Z
translate from https://stackoverflow.com:/questions/1134388/stdendl-is-of-unknown-type-when-overloading-operator