无法从 spdlog 中格式化参数

Posted

技术标签:

【中文标题】无法从 spdlog 中格式化参数【英文标题】:Cannot format argument from within spdlog 【发布时间】:2020-06-11 08:28:46 【问题描述】:

我正在尝试使用spdlog。我将它与我的代码合并,但现在我收到以下错误:

....fmt\core.h(1016): error C2338: Cannot format argument. To make type T formattable provide a formatter<T> specialization: https://fmt.dev/latest/api.html#formatting-user-defined-types
  ....fmt/core.h(1013): note: while compiling class template member function 'int fmt::v6::internal::arg_mapper<Context>::map(...)'
          with
          [
              Context=context
          ]
  ....fmt/core.h(1213): note: see reference to function template instantiation 'int fmt::v6::internal::arg_mapper<Context>::map(...)' being compiled
          with
          [
              Context=context
          ]
  ....fmt/core.h(1027): note: see reference to class template instantiation 'fmt::v6::internal::arg_mapper<Context>' being compiled
          with
          [
              Context=context
          ]
  ....fmt/core.h(1198): note: see reference to alias template instantiation 'fmt::v6::internal::mapped_type_constant<int,context>' being compiled
  ....fmt/core.h(1342): note: see reference to function template instantiation 'unsigned __int64 fmt::v6::internal::encode_types<Context,int,>(void)' being compiled
          with
          [
              Context=context
          ]
  ....fmt/format.h(3375): note: see reference to class template instantiation 'fmt::v6::format_arg_store<context,int>' being compiled
  ....spdlog/details/fmt_helper.h(49): note: see reference to function template instantiation 'std::back_insert_iterator<fmt::v6::internal::buffer<char>> fmt::v6::format_to<char[6],int&,250,char>(fmt::v6::basic_memory_buffer<char,250,std::allocator<char>> &,const S (&),int &)' being compiled
          with
          [
              S=char [6]
          ]

... 这是错误消息的结尾。它永远不会到达我的代码,所以我不知道在哪里看。任何想法可能是什么原因?

spdlog 是 1.6.1 版。最后一个错误行来自这里:

inline void pad2(int n, memory_buf_t &dest)

    if (n >= 0 && n < 100) // 0-99
    
        dest.push_back(static_cast<char>('0' + n / 10));
        dest.push_back(static_cast<char>('0' + n % 10));
    
    else // unlikely, but just in case, let fmt deal with it
    
        fmt::format_to(dest, ":02", n);  // <--- HERE
    

在我看来并没有什么特别的错误。


更新:在注释掉所有 spdlog 调用的一些尝试和错误之后,我将其缩小为:

spdlog::info("Foo", Point1, 2);

Point 是我自己命名空间中的类。我确实为它提供了一种打印自己的方式:

template<typename OStream>
OStream &operator<<(OStream &os, const Point &p) 
    return os << "[" << p.x << ", " << p.y << "]";

【问题讨论】:

您能提供您的Point 课程吗?你在里面声明了operator &lt;&lt;吗? 您能否提供更多代码,您可以拨打spdlog::info 添加#include &lt;spdlog/fmt/ostr.h&gt; 如果您希望使用operator&lt;&lt; 格式化用户定义的类型,则需要提到的特殊包含@PiotrSkotnicki。否则您需要提供fmt::formatter class specialization。 @JorgeBellon 我有一个代码,可以打印用户定义的类,但我没有手动包含该文件并且它可以工作 【参考方案1】:

spdlog 使用fmt 库来格式化输出文本,这需要&lt;fmt/ostream.h&gt; 头文件to be included 才能启用类似std::ostream 的支持。

无论使用fmt 库的外部实现,还是来自spdlog 源本身的库,都有一个特殊的标头&lt;spdlog/fmt/ostr.h&gt;,其中包含正在使用的文件版本。

包含后,spdlog 应该可以使用您的operator&lt;&lt;

或者,您可以创建一个自定义格式化程序,它也能够解析格式化字符串:

template <>
struct fmt::formatter<Point> 
    constexpr auto parse(format_parse_context& ctx) 
        return ctx.end();
    

    template <typename Context>
    auto format(const Point& p, Context& ctx) 
        return format_to(ctx.out(), "[, ]", p.x, p.y);
    
;

【讨论】:

以上是关于无法从 spdlog 中格式化参数的主要内容,如果未能解决你的问题,请参考以下文章

为自定义类型扩展 spdlog

spdlog 基本结构分析

如何转义 spdlog 消息?

带有 gtest 框架的 Spdlog 记录器无法正常工作

spdlog:无法刷新/写入文件

在 CMake 项目中找不到 spdlog.h