如何使用标头中定义的输出流运算符

How to use an output stream operator defined in a header

本文关键字:输出流 运算符 定义 何使用      更新时间:2023-10-16

我希望能够将任何std::vector<T>的内容附加到输出流中。我找到了这段代码:

#ifndef DEBUG_H_
#define DEBUG_H_
#include <vector>
template < class T >
std::ostream& operator << (std::ostream& os, const std::vector<T>& v)
{
    os << "[";
    for (typename std::vector<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii)
    {
        os << " " << *ii;
    }
    os << "]";
    return os;
}

#endif /* DEBUG_H_ */

并放入标题Debug.h.如何在项目中使用此运算符?

编辑:我已经验证了这在单元测试中有效:

#include "Debug.h"
TEST_F(AuxGTest, testVectorDebug) {
    std::vector<int> vec(10, 42);
    std::cout << "vec: " << vec << std::endl;
}

但是将其与log4cxx的日志语句一起使用不起作用:

#include <log4cxx>
#include "Debug.h"
namespace Foo {
    class Bar { 
        void foo() {
            std::vector<int> vec(10, 42);
            DEBUG("vec: " << vec);
        }
    }
}

这将生成以下编译器消息:

/usr/local/Cellar/log4cxx/0.10.0/include/log4cxx/helpers/messagebuffer.h:190:47: error: cannot bind 'std::basic_ostream<char>' lvalue to 'std::basic_ostream<char>&&'

你想在哪里使用它? 正如所宣称的,它在全球命名空间,因此除非 T 是类型,否则 ADL 不会找到它在全局命名空间中定义。 它不会被正常查找(如果位于全局命名空间以外的命名空间中(命名空间,并且该命名空间中有一个operator<<(该命名空间会隐藏它(。 如果在 中调用,也找不到它一个模板,如果任何参数是依赖的,因为从属名称查找仅使用 ADL。

当然,除了玩具,你真的不想这样做。程序。 std::vector的不同用途将需要不同的输出格式;最好将 std::vector类中,并operator<<定义类,用于每种不同的语义用法。 (对于玩具程序,您可以在命名空间std中定义运算符。 未定义行为,但是由于没有其他人会看到代码,或者必须维护它,如果不维护它,这不是世界末日工作...

编辑:

由于您似乎将其用于某种跟踪或调试:这是有意义的一种情况支持std::vector的统一输出,因为它用于输出内部状态。 另一方面,这很常见要包装ostream的情况,如下所示:

class Logger
{
    std::ostream* myDest;
public:
    Logger( std::ostream* dest )
        : myDest( dest )
    {
    }
    template <typename T>
    Logger& operator<<( T const& value )
    {
        if ( myDest != NULL ) {
            *myDest << value;
        }
        return *this;
    }
};

这允许日志记录的运行时配置(加上自动插入诸如__FILE____LINE__之类的内容,如果您使用一个宏来获取 Logger 的实例(;您的宏DEBUG可能是这样的:

#define DEBUG getLogger( TRACELEVEL_DEBUG, __FILE__, __LINE__ )

其中getLogger是一个返回Logger的全局函数使用正确的ostream初始化(或空指针,如果该级别的日志记录不处于活动状态(。 完成此操作后,您可以添加特殊功能,例如:

template <typename T>
Logger& Logger::operator<<( std::vector<T> const& value )
{
    if ( myDest != NULL ) {
        //  your code here...
    }
    return *this;
}

由于其中一个参数,<<运算符将是一个Logger实例,ADL无论如何都会找到运算符。

关于 log4cxx 的用户定义运算符,也存在类似的问题。我通过建议将运算符放在 log4cxx::helpers 命名空间中来回答这个问题。看。