Mordachai
Mordachai

Reputation: 9662

How to format pointers using fmt library?

I'm taking up some folks advice and looking into the fmt library: http://fmtlib.net

It appears to have the features I need, and claims to support %p (pointer), but when compiling my code which uses a %p I get a long string of template errors (incomprehensible). I'll post them at the end of this.

if I pull out the %p and the corresponding pointer argument, then it compiles on VS2017 c++17.

However, I'm at a loss as to how to either decode the template errors, or to get some insight as to why it won't accept a %p argument in the first place.

I've tried casting the argument to a (void*) - same issue.
I've tried using the python style syntax in the formatter {} - same issue.
I've broken out the %p bits separately from the rest of the formatting - same issue.

I see that there is support for user-types - but in this case I just want to output this as a raw pointer value. I could just skip it, after all how valuable can the pointer address be, really? But of course that means more work during conversion from sprintf to fmt::format to hunt down all %p and "do something with them" such as elide them.

But the docs seem to indicate that %p is supported - http://fmtlib.net/latest/syntax.html (about 3/4 of the way down - search on 'pointer' or 'p').

Here's the calling function: (note: pAccels is declared as 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);
    }

Here's the diagnostic spewage:

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'

Upvotes: 10

Views: 17356

Answers (1)

vitaut
vitaut

Reputation: 55595

To format a pointer you can either cast it to void*:

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

or wrap it in fmt::ptr:

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

Working example on godbolt: https://godbolt.org/z/sCNbjr

Note that format uses Python-like format string syntax, not printf's and returns a std::string object.

Upvotes: 20

Related Questions