【问题标题】:How to format pointers using fmt library?如何使用 fmt 库格式化指针?
【发布时间】:2019-09-27 20:36:13
【问题描述】:

我正在接受一些人的建议并研究 fmt 库: http://fmtlib.net

它似乎具有我需要的功能,并声称支持%p(指针),但是在编译使用 %p 的代码时,我得到一长串模板错误(难以理解)。我会在最后贴出来。

如果我取出%p 和相应的指针参数,那么它会在VS2017 c++17 上编译。

但是,我不知道如何解码模板错误,或者了解为什么它首先不接受 %p 参数。

我尝试将参数转换为 (void*) - 同样的问题。
我尝试在格式化程序 {} 中使用 python 样式语法 - 同样的问题。
我已经将 %p 位与其他格式分开 - 同样的问题。

我看到支持用户类型 - 但在这种情况下,我只想将其作为原始指针值输出。我可以跳过它,毕竟指针地址有多大价值,真的吗?但这当然意味着在从sprintf 转换为fmt::format 的过程中需要做更多的工作来追捕所有 %p 并“对他们做点什么”,比如避开他们。

但文档似乎表明支持 %p - http://fmtlib.net/latest/syntax.html(大约下降了 3/4 - 搜索“指针”或“p”)。

这里是调用函​​数:(注意:pAccels 被声明为const ACCEL *

    m_hAccel = ::CreateAcceleratorTable(const_cast<LPACCEL>(pAccels), (int)count);
    if (!m_hAccel)
    {
        auto error = GetLastError();
        throw CWinAPIErrorException(__FUNCTION__, "CreateAcceleratorTable", fmt::format("%p,%u", pAccels, count), error);
    }

这是诊断结果:

1>c:\users\steve\source\fmt\include\fmt\core.h(1073): error C2825: 'fmt::v5::internal::get_type<Context,Arg>::value_type': must be a class or namespace when followed by '::'
1>        with
1>        [
1>            Context=fmt::v5::basic_format_context<std::back_insert_iterator<fmt::v5::internal::buffer<char>>,char>,
1>            Arg=const ACCEL *
1>        ]
1>c:\users\steve\source\fmt\include\fmt\core.h(1081): note: see reference to class template instantiation 'fmt::v5::internal::get_type<Context,Arg>' being compiled
1>        with
1>        [
1>            Context=fmt::v5::basic_format_context<std::back_insert_iterator<fmt::v5::internal::buffer<char>>,char>,
1>            Arg=const ACCEL *
1>        ]
1>c:\users\steve\source\fmt\include\fmt\core.h(1190): note: see reference to function template instantiation 'unsigned __int64 fmt::v5::internal::get_types<Context,const ACCEL*,size_t>(void)' being compiled
1>        with
1>        [
1>            Context=fmt::v5::basic_format_context<std::back_insert_iterator<fmt::v5::internal::buffer<char>>,char>
1>        ]
1>c:\users\steve\source\fmt\include\fmt\core.h(1190): note: while compiling class template member function 'unsigned __int64 fmt::v5::format_arg_store<fmt::v5::basic_format_context<std::back_insert_iterator<fmt::v5::internal::buffer<Char>>,Char>,const ACCEL *,size_t>::get_types(void)'
1>        with
1>        [
1>            Char=char
1>        ]
1>c:\users\steve\source\fmt\include\fmt\core.h(1478): note: see reference to class template instantiation 'fmt::v5::format_arg_store<fmt::v5::basic_format_context<std::back_insert_iterator<fmt::v5::internal::buffer<Char>>,Char>,const ACCEL *,size_t>' being compiled
1>        with
1>        [
1>            Char=char
1>        ]
1>c:\users\steve\source\tbx\wapi\acceleratortable.cpp(58): note: see reference to function template instantiation 'std::basic_string<char,std::char_traits<char>,std::allocator<char>> fmt::v5::format<char[6],const ACCEL*,size_t,0>(const S (&),const ACCEL *const &,const size_t &)' being compiled
1>        with
1>        [
1>            S=char [6]
1>        ]
1>c:\users\steve\source\fmt\include\fmt\core.h(1073): error C2510: 'value_type': left of '::' must be a class/struct/union
1>c:\users\steve\source\fmt\include\fmt\core.h(1073): error C2065: 'type_tag': undeclared identifier
1>c:\users\steve\source\fmt\include\fmt\core.h(1073): error C2131: expression did not evaluate to a constant
1>c:\users\steve\source\fmt\include\fmt\core.h(1073): note: a non-constant (sub-)expression was encountered
1>c:\users\steve\source\fmt\include\fmt\core.h(1197): error C2131: expression did not evaluate to a constant
1>c:\users\steve\source\fmt\include\fmt\core.h(1082): note: failure was caused by non-constant arguments or reference to a non-constant symbol
1>c:\users\steve\source\fmt\include\fmt\core.h(1082): note: see usage of 'value'

【问题讨论】:

  • 你必须先投到void*
  • 你有没有测试过%p是否完全被指针破坏了?如果你给它一个普通的旧int * 怎么办?会发生什么?

标签: c++ templates compiler-errors formatting fmt


【解决方案1】:

要格式化指针,您可以将其转换为void*

std::string s = fmt::format("{},{}", static_cast<void*>(pAccels), count);

或将其包裹在fmt::ptr:

std::string s = fmt::format("{},{}", fmt::ptr(pAccels), count);

godbolt 上的工作示例:https://godbolt.org/z/sCNbjr

请注意,format 使用类似于 Python 的格式字符串语法,而不是 printf,并返回 std::string 对象。

【讨论】:

  • 它还支持 printf 样式 %s 等。至少文档说得这么多。我确实尝试将pAccels 转换为void* 并遇到了同样的问题。但我没有运行 CMake - 这可能会解决这个问题。
  • 是的,但是对于%s,您需要使用fmt::sprintf,而不是fmt::format
  • 你不需要 CMake,查看使用 vanilla MSVC 的 Godbolt 链接。该错误可能是因为您将 std::string 传递给需要 C 字符串而不是指针格式的 API。
  • 不知道为什么 - 要么我累了,要么编译器将以后对 format() 的调用标记为错误,因为之前的调用没有发出错误?不知道。无论如何,简单地投射到void* 是诀窍。我需要将其他句柄转换为void*UINT_PTR,具体取决于我是否尝试将它们分别输出为%p%X
猜你喜欢
  • 1970-01-01
  • 2021-08-04
  • 2019-11-13
  • 2021-10-02
  • 1970-01-01
  • 2021-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多