重载运算符<<<<<<<<<<<

时间:2009-07-15 22:06:43

标签: c++ stl operator-overloading

我重载了运算符<<

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

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

工作但是:

my_stream << endl;

出现编译错误:

  

错误C2678:二进制'&lt;&lt;' :找不到哪个运算符带有'UIStream'类型的左手操作数(或者没有可接受的转换)

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

6 个答案:

答案 0 :(得分:74)

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

希望这能让您更好地了解这些事情是如何运作的。

答案 1 :(得分:35)

问题是std::endl是一个功能模板,作为您的运营商<< 是。所以当你写:

my_stream << endl;

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

因此,您必须编写运算符<<的其他非模板重载 与操纵者合作。他们的原型看起来像:

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

(还有其他两个,将std::ostream替换为std::basic_ios<char>std::ios_base,如果您想要允许所有内容,还必须提供typedef std::ostream& (*ostream_manipulator)(std::ostream&); UIStream& operator<<(UIStream& os, ostream_manipulator pf) { return operator<< <ostream_manipulator> (os, pf); } 操纵者)和他们的实施将非常相似 你的模板。事实上,你可以使用你的模板 像这样的实现:

streambuf

最后一点,经常编写自定义{{1}}通常是更好的方法 实现应用于您正在使用的技术的尝试。

答案 2 :(得分:6)

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

    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/

希望这可以帮助某人。

答案 3 :(得分:4)

有关扩展IOStream的更好方法,请参阅here。 (有点过时,并为VC 6量身定制,所以你必须带上一粒盐)

关键是要使编码器工作(和endl,它们都输出“\ n”和刷新是一个算符)你需要实现完整的ostream接口。

答案 4 :(得分:3)

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中的{1}}版本。

编辑:看起来喜欢GMan的答案更好。他也得到std::iostream工作!

答案 5 :(得分:1)

除了接受的答案,使用C ++ 11可以为类型重载class SalesController < ApplicationController load_and_authorize_resource before_action :authenticate_user! def create @order = Order.find(params[:order_id]) @sale = @order.sales.create(params[:sale].permit(:product, :product_group, :discount, :order_id, :user_id, :multiplier)) redirect_to order_path(@order) end

operator<<