繁体   English   中英

重载 operator< 时 std::endl 的类型未知

[英]std::endl is of unknown type when overloading operator<<

我重载了运算符 <<

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

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

有效但:

my_stream << endl;

给出编译错误:

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

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

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

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

问题在于std::endl是一个函数模板,就像您的运算符<< 所以当你写:

my_stream << endl;

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

所以你必须编写额外的、非模板的、operator <<重载来使用操纵器。 他们的原型将如下所示:

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

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

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

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

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

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

主程序

int main(){

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

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

希望这可以帮助某人。

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

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

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

要使endl工作,您需要实现一个带有指向函数的指针的operator<<版本,因为这就是处理诸如endl之类的操纵器的方式,即

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

或者

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM