【问题标题】:How to use an output stream operator defined in a header如何使用在标头中定义的输出流运算符
【发布时间】:2023-03-23 02:02:02
【问题描述】:

我希望能够将任何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>&&'

【问题讨论】:

  • 大多数情况下,您只需在要使用运算符的源文件中包含标头,然后执行std::cerr &lt;&lt; your_vector;之类的操作
  • @JerryCoffin 如果代码在模板里试试,T 是基本类型之一,如int。 (它可能仍然适用于 MSVC,但不适用于实现 C++98 或更高版本的编译器。)
  • @JamesKanze:我将这个问题解释为一个简单的问题,即如何部署此代码以在项目中使用,而不是更复杂的问题是如何实际使代码在任何情况下工作,但最琐碎的条件(但特别是在重读问题之后,我会公开承认这可能是一个错误)。

标签: c++ string stl log4cxx


【解决方案1】:

你想在哪里使用它?正如声明的那样,它在全球范围内 命名空间,因此 ADL 不会找到它,除非 T 是一个类型 在全局命名空间中定义。它不会被找到 如果您在全局以外的命名空间中,则正常查找 命名空间,并且在该命名空间中有一个operator&lt;&lt;(其中 会隐藏它)。如果在中调用它也不会被发现 一个模板,如果任何参数是依赖的,因为 从属名称查找仅使用 ADL。

当然,除了玩具,你真的不想这样做 程式。 std::vector 的不同用途需要 不同的输出格式;包裹起来要好得多 std::vector 在一个类中,并定义 operator&lt;&lt; 为 类,用于每种不同的语义用途。 (对于玩具程序,您 可以在命名空间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;
}

由于其中一个参数,&lt;&lt; 运算符将是 Logger 的实例,ADL 将找到运算符,无论如何。

【讨论】:

  • 我试图通过一个模拟示例来明确我在哪里使用它。实际的代码会非常冗长。
  • 您能否指出一个代码示例,其中包含 std::vector 并添加了运算符 &lt;&lt;
  • @cls 不是随便的,但它似乎不是一个困难的概念。您定义一个包含std::vector 的类(为其提供一个适合其在应用程序中的角色的接口),然后为该类编写一个operator&lt;&lt;
  • @cls 你的例子:"log4cxx" 中有什么?特别是,它是否会导致编译器需要 ADL 才能找到您的 operator&lt;&lt;
  • @cls 调试输出可能是我声明的一个例外,即您不想要vector 的全局输出。我已经编辑了我的答案以显示我如何处理这个问题。
【解决方案2】:

有一个类似的question 关于log4cxx 的用户定义运算符。我answered 建议将运算符放在log4cxx::helpers 命名空间中。见。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-06
    • 2013-08-10
    • 2011-05-03
    相关资源
    最近更新 更多