C++ 重载 operator<< 时 std::endl 是未知类型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1134388/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 18:57:33  来源:igfitidea点击:

std::endl is of unknown type when overloading operator<<

c++stloperator-overloading

提问by Kazoom

I overloaded operator <<

我重载了运算符 <<

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

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

Works but:

有效但:

my_stream << endl;

Gives compilation error:

给出编译错误:

error C2678: binary '<<' : no operator found which takes a left-hand operand of type 'UIStream' (or there is no acceptable conversion)

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

What is the work around for making my_stream << endlwork?

工作的解决方法是my_stream << endl什么?

回答by GManNickG

std::endlis a function and std::coututilizes it by implementing operator<<to take a function pointer with the same signature as std::endl.

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

In there, it calls the function, and forwards the return value.

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

Here is a code example:

这是一个代码示例:

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

Hopefully this gives you a better idea of how these things work.

希望这能让你更好地了解这些东西是如何工作的。

回答by AProgrammer

The problem is that std::endlis a function template, as your operator <<is. So when you write:

问题在于它std::endl是一个函数模板,就像您的操作员一样<<。所以当你写:

my_stream << endl;

you'll like the compiler to deduce the template parameters for the operator as well as for endl. This isn't possible.

您会喜欢编译器为运算符和 for 推导出模板参数endl。这是不可能的。

So you have to write additional, non template, overloads of operator <<to work with manipulators. Their prototype will look like:

所以你必须编写额外的、非模板的、运算符的重载<<来与操纵器一起工作。他们的原型将如下所示:

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

(there are two others, replacing std::ostreamby std::basic_ios<char>and std::ios_base, which you have also to provide if you want to allow all manipulators) and their implementation will be very similar to the one of your templates. In fact, so similar that you can use your template for implementation like this:

(还有另外两个,std::ostreamstd::basic_ios<char>and 替换,std::ios_base如果您想允许所有操纵器,您还必须提供它们)并且它们的实现将与您的模板之一非常相似。事实上,非常相似,您可以使用您的模板来实现这样的:

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

A final note, often writing a custom streambufis often a better way to achieve what one try to achieve applying to technique you are using.

最后一点,通常编写自定义streambuf通常是实现人们尝试实现的应用到您正在使用的技术的更好方法。

回答by Lucas Casagrande

I did this to solve my problem, here is part of my code:

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

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

I got the reference in here http://www.cplusplus.com/forum/general/49590/

我在这里得到了参考http://www.cplusplus.com/forum/general/49590/

Hope this can help someone.

希望这可以帮助某人。

回答by EFraim

See herefor better ways of extending IOStreams. (A bit outdated, and tailored for VC 6, so you will have to take it with a grain of salt)

有关扩展 IOStreams 的更好方法,请参见此处。(有点过时了,是为 VC 6 量身定做的,所以你必须小心翼翼地接受它)

The point is that to make functors work (and endl, which both outputs "\n" and flushes is a functor) you need to implement the full ostream interface.

关键是要使函子工作(和 endl,输出 "\n" 和刷新都是函子),您需要实现完整的 ostream 接口。

回答by Troubadour

The stdstreams are not designed to be subclassed as they have no virtual methods so I don't think you'll get too far with that. You can try aggregating a std::ostream to do the work though.

std流不设计,因为他们没有虚方法被子类,所以我不认为你会得到与该太远。不过,您可以尝试聚合 std::ostream 来完成这项工作。

To make endlwork you need to implement a version of operator<<that takes a pointer-to-function as that is how the manipulators such as endlare handled i.e.

为了endl工作,你需要实现一个版本,operator<<它需要一个指向函数的指针,因为这就是操纵器endl的处理方式,即

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

or

或者

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

Now std::endlis a function that takes and returns a reference to a std::basic_ostream so that won't work directly with your stream so you'll need to make your own version which calls through to the std::endlversion in your aggregated std::iostream.

现在std::endl是一个函数,它接受并返回对 std::basic_ostream 的引用,因此它不能直接与您的流一起使用,因此您需要制作自己的版本,该std::endl版本调用您的聚合std::iostream.

Edit: Looks likes GMan's answer is better. He gets std::endlworking too!

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

回答by AlwaysLearning

In addition to the accepted answer, with C++11 it is possible to overload operator<<for the type:

除了接受的答案之外,使用 C++11 还可以重载operator<<该类型:

decltype(std::endl<char, std::char_traits<char>>)