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'
To use the {fmt} library, add fmt/core. h , fmt/format. h , fmt/format-inl. h , src/format.cc and optionally other headers from a release archive or the Git repository to your project.
{fmt} is an open-source formatting library providing a fast and safe alternative to C stdio and C++ iostreams. What users say: Thanks for creating this library. It's been a hole in C++ for a long time. I've used both boost::format and loki::SPrintf , and neither felt like the right answer.
'g' General format. For a given precision p >= 1 , this rounds the number to p significant digits and then formats the result in either fixed-point format or in scientific notation, depending on its magnitude.
fmt stands for the Format package. This package allows to format basic strings, values, or anything and print them or collect user input from the console, or write into a file using a writer or even print customized fancy error messages. This package is all about formatting input and output.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With