当前位置:  开发笔记 > 编程语言 > 正文

如何重载运算符<<不接受或返回ostream

如何解决《如何重载运算符<<不接受或返回ostream》经验,为你挑选了1个好方法。

原始问题

我正在编写一个日志类,其目标是能够执行此操作:

// thread one
Logger() << "Some string" << std::ios::hex << 45;
// thread two
Logger() << L"Some wide string" << std::endl;

目前我的Logger标题看起来像这样:

#pragma once;
#include     
class Logger
{
public:
    Logger();
    ~Logger();

    std::ostream* out_stream;
};

template 
Logger& operator<< (Logger& logger, T thing) {
    *logger.out_stream << thing;
    return logger;
}

关于这门课的一些注意事项

    跨平台兼容性不是问题.

    在Logger.cpp里面有一个单例类,负责创建"真正的"ostream.

    Logger构造函数和解构函数执行单例的必要锁定.

我有三个问题:

如何使operator << function成为朋友或成员,以便将out_stream设置为私有?

如何使操作符<<函数适用于操纵器?

我如何添加一个特化,以便如果T是WCHAR*或std :: wstring,它会在将它传递给out_stream之前将其转换为char*或std :: string?(我可以进行转换.在我的情况下,丢失高的unicode字符不是问题.)

在答案中学到的东西总结:

把模板放在朋友之前而不是之后.

std :: ios :: hex不是操纵者.std :: hex是一个操纵器.

最终结果

#pragma once
#include 
#include 

std::string ConvertWstringToString(std::wstring wstr);

class Logger
{
public:
    Logger();
    ~Logger();

    template 
    Logger& operator<< (T data) {
        *out << data;
        return *this;
    }
    Logger& operator<< (std::wstring data) {
        return *this << ConvertWstringToString(data);
    }
    Logger& operator<< (const wchar_t* data) {
        std::wstring str(data);
        return *this << str;
    }

private:
    std::ostream* out;
};

Johannes Sch.. 7

您可以使用友元定义,它将在类的周围命名空间中定义运算符,并使其仅对运算符重载分辨率可见(不能使用:: operator << ...语法手动调用):

class Logger
{
public:
    Logger();
    ~Logger();

    std::ostream* out_stream;

    template 
    friend Logger& operator<< (Logger& logger, T thing) {
        *logger.out_stream << thing;
        return logger;
    }

    /* special treatment for std::wstring. just overload the operator! No need
     * to specialize it. */
    friend Logger& operator<< (Logger& logger, const std::wstring & wstr) {
        /* do something here */
    }

};

另一种方法是,保持代码不变,只需将操作符<<模板设为好友,就可以将此行添加到类定义中:

template 
friend Logger& operator<< (Logger& logger, T thing);

对于操纵器问题,我会给你我前一段时间写的代码:

#include 
#include 
using namespace std;

template >
struct logger{
    typedef std::basic_ostream ostream_type;
    typedef ostream_type& (*manip_type)(ostream_type&);
    logger(ostream_type& os):os(os){}
    logger &operator<<(manip_type pfn) {
        if(pfn == static_cast(std::endl)) {
            time_t t = time(0);
            os << " --- " << ctime(&t) << pfn; 
        } else
            os << pfn;
        return *this; 
    }
    template 
    logger &operator<<(T const& t) { 
        os << t; 
        return *this;
    }
private:        
    ostream_type & os;
};

namespace { logger clogged(cout); }
int main() { clogged << "something with log functionality" << std::endl; }

};

请注意,它是std :: hex,但不是std :: ios :: hex.后者用作setf流的功能的操纵器标志.请注意,对于您的示例,不需要对操纵器进行特殊处理.上面对std :: endl的特殊处理只是需要因为我在使用std :: endl时会另外流式传输时间.



1> Johannes Sch..:

您可以使用友元定义,它将在类的周围命名空间中定义运算符,并使其仅对运算符重载分辨率可见(不能使用:: operator << ...语法手动调用):

class Logger
{
public:
    Logger();
    ~Logger();

    std::ostream* out_stream;

    template 
    friend Logger& operator<< (Logger& logger, T thing) {
        *logger.out_stream << thing;
        return logger;
    }

    /* special treatment for std::wstring. just overload the operator! No need
     * to specialize it. */
    friend Logger& operator<< (Logger& logger, const std::wstring & wstr) {
        /* do something here */
    }

};

另一种方法是,保持代码不变,只需将操作符<<模板设为好友,就可以将此行添加到类定义中:

template 
friend Logger& operator<< (Logger& logger, T thing);

对于操纵器问题,我会给你我前一段时间写的代码:

#include 
#include 
using namespace std;

template >
struct logger{
    typedef std::basic_ostream ostream_type;
    typedef ostream_type& (*manip_type)(ostream_type&);
    logger(ostream_type& os):os(os){}
    logger &operator<<(manip_type pfn) {
        if(pfn == static_cast(std::endl)) {
            time_t t = time(0);
            os << " --- " << ctime(&t) << pfn; 
        } else
            os << pfn;
        return *this; 
    }
    template 
    logger &operator<<(T const& t) { 
        os << t; 
        return *this;
    }
private:        
    ostream_type & os;
};

namespace { logger clogged(cout); }
int main() { clogged << "something with log functionality" << std::endl; }

};

请注意,它是std :: hex,但不是std :: ios :: hex.后者用作setf流的功能的操纵器标志.请注意,对于您的示例,不需要对操纵器进行特殊处理.上面对std :: endl的特殊处理只是需要因为我在使用std :: endl时会另外流式传输时间.

推荐阅读
有风吹过best
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有