【问题标题】:How to define output stream operator for boost log and a custom type如何为 boost log 和自定义类型定义输出流运算符
【发布时间】:2018-01-27 14:35:22
【问题描述】:

我能够为一个简单的结构定义输出流运算符,但是,不能为 std::array 定义。以下代码无法编译。出了什么问题,我该如何解决?

#include <array>
#include <iostream>
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>

using hash_t = std::array< unsigned char, 32 >;

std::ostream& operator<< ( std::ostream& os, hash_t const& arr )
{
    os << "ole!";
    return os;
}

int main(int, char*[])
{
    hash_t arr;
    std::cerr << arr << std::endl; // complies cleanly
    BOOST_LOG_TRIVIAL(debug) << arr; // Error
    return 0;
}

错误来了。

GCC(提升 1.55,gcc-4.9.2):

In file included from /usr/include/boost/log/sources/record_ostream.hpp:31:0,
                 from /usr/include/boost/log/trivial.hpp:23,
                 from trival.cpp:4:
/usr/include/boost/log/utility/formatting_ostream.hpp: In instantiation of ‘boost::log::v2s_mt_posix::basic_formatting_ostream<CharT, TraitsT, AllocatorT>& boost::log::v2s_mt_posix::operator<<(boost::log::v2s_mt_posix::basic_formatting_ostream<CharT, TraitsT, AllocatorT>&, const T&) [with CharT = char; TraitsT = std::char_traits<char>; AllocatorT = std::allocator<char>; T = std::array<unsigned char, 32ul>]’:
trival.cpp:18:30:   required from here
/usr/include/boost/log/utility/formatting_ostream.hpp:710:19: error: cannot bind ‘boost::log::v2s_mt_posix::basic_formatting_ostream<char>::ostream_type {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
     strm.stream() << value;
                   ^
In file included from /usr/include/c++/4.9/iostream:39:0,
                 from trival.cpp:2:
/usr/include/c++/4.9/ostream:602:5: note: initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = std::array<unsigned char, 32ul>]’
     operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)

Clang 错误(提升 1.64,clang-800.0.42.1):

In file included from /usr/local/include/boost/log/trivial.hpp:23:
In file included from /usr/local/include/boost/log/sources/record_ostream.hpp:36:
/usr/local/include/boost/log/utility/formatting_ostream.hpp:878:19: error: invalid operands to binary expression ('ostream_type' (aka
      'basic_ostream<char, std::__1::char_traits<char> >') and 'std::__1::array<unsigned char, 32>')
    strm.stream() << value;
    ~~~~~~~~~~~~~ ^  ~~~~~
/usr/local/include/boost/log/sources/record_ostream.hpp:390:51: note: in instantiation of function template specialization
      'boost::log::v2_mt_posix::operator<<<boost::log::v2_mt_posix::basic_formatting_ostream<char, std::__1::char_traits<char>, std::__1::allocator<char> >,
      std::__1::array<unsigned char, 32> >' requested here
    static_cast< formatting_ostream_type& >(strm) << value;
                                                  ^
/Users/adam/GitPen/BoostLog/trival/trival.cpp:18:27: note: in instantiation of function template specialization
      'boost::log::v2_mt_posix::operator<<<boost::log::v2_mt_posix::basic_record_ostream<char>, std::__1::array<unsigned char, 32> >' requested here
        BOOST_LOG_TRIVIAL(debug) << arr;

【问题讨论】:

    标签: c++ templates boost-log stream-operators


    【解决方案1】:

    你可能不喜欢这个答案。

    要让它在此刻正常工作,您需要将您的 operator&lt;&lt; 添加到 namespace std

    namespace std{
       std::ostream& operator<< ( std::ostream& os, const hash_t& arr )
       {/*...*/}
    }
    

    由于 ADL 的工作原理,它只考虑 operator&lt;&lt; 及其在 namespace std 中的特化

    你不会喜欢它,因为将这个函数添加到 namespace std 是不合法的:

    [命名空间.std]

    如果 C++ 程序将声明或定义添加到命名空间 std 或 除非另有说明,否则命名空间 std 内的命名空间。程序可以添加模板特化 仅当声明依赖于用户定义的类型时,任何标准库模板才能命名空间 std 并且专业化满足原始模板的标准库要求并且没有明确 禁止。

    也许最简单的做法是从std 类型继承(而不做其他任何事情):

    struct hash_t : std::array< unsigned char, 32 >{};
    

    【讨论】:

    • 啊,是ADL!我认为继承可以解决问题。与其说using hash_t = std::array&lt; char, 2 &gt;;,不如说struct hash_t : std::array&lt; char, 2 &gt; {};
    • @AndrewDwojc:完全正确
    • 这个答案也很重要:stackoverflow.com/questions/32524347/… 当不希望继承时,操纵器方法可能更可取(例如,您不希望 hash_t 成为新类型),太乏味(例如,您必须将许多构造函数转发给基类)或不可能(例如类型为final)。
    • 是的。我对你的答案投了赞成票,并选择了struct hash_t : std::array&lt; char, 32 &gt; {}; 把戏。然而,我意识到一旦我为其他标准类型定义了&lt;&lt;(例如vector&lt; T &gt;),我将再次遇到同样的问题。当您看到那些长长的编译器消息时,很高兴知道它只是 ADL。
    猜你喜欢
    • 1970-01-01
    • 2021-06-11
    • 2015-04-10
    • 1970-01-01
    • 2020-10-10
    • 2019-07-28
    • 2021-11-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多