4

I want to have fmt::format return a wstring from EA's STL, but when I try to modify this code from the docs—which works fine:

// Prints formatted error message.
void
vreport_error(const char *format, fmt::format_args args) {
    fmt::print("Error: ");
    fmt::vprint(format, args);
}

template <typename... Args>
void
report_error(const char *format, const Args &... args) {
    vreport_error(format, fmt::make_format_args(args...));
}

to use wchar_t instead of char:

// Prints formatted error message.
void vreport_error2(const wchar_t *format, fmt::format_args args);
template <typename... Args>
void
report_error2(const wchar_t *format, const Args &... args) {
    vreport_error2(format, fmt::make_format_args(args...));
}

I get:

2>fmt\core.h(1219,1): error C2665:  'fmt::v5::basic_format_args<fmt::v5::wformat_context>::basic_format_args': none of the 4 overloads could convert all the argument types
2>fmt\core.h(1219,1): error C2665:       : basic_format_args<wformat_context>(std::forward<Args>(args)...) {}
2>fmt\core.h(1219,1): error C2665: ^ (compiling source file ..\core\typedefs.cpp)
2>fmt\core.h(1207,1): message :  could be 'fmt::v5::basic_format_args<fmt::v5::wformat_context>::basic_format_args(fmt::v5::basic_format_args<fmt::v5::wformat_context> &&)'
2>fmt\core.h(1207,1): message : };
2>fmt\core.h(1207,1): message : ^ (compiling source file ..\core\typedefs.cpp)
2>fmt\core.h(1207,1): message :  or       'fmt::v5::basic_format_args<fmt::v5::wformat_context>::basic_format_args(const fmt::v5::basic_format_args<fmt::v5::wformat_context> &)'
2>fmt\core.h(1207,1): message : };
2>fmt\core.h(1207,1): message : ^ (compiling source file ..\core\typedefs.cpp)
2>fmt\core.h(1189,3): message :  or       'fmt::v5::basic_format_args<fmt::v5::wformat_context>::basic_format_args(const fmt::v5::basic_format_arg<Context> *,int)'
2>fmt\core.h(1189,3): message :         with
2>fmt\core.h(1189,3): message :         [
2>fmt\core.h(1189,3): message :             Context=fmt::v5::wformat_context
2>fmt\core.h(1189,3): message :         ]
2>fmt\core.h(1189,3): message :   basic_format_args(const format_arg* args, int count)
2>fmt\core.h(1189,3): message :   ^ (compiling source file ..\core\typedefs.cpp)
2>fmt\core.h(1171,3): message :  or       'fmt::v5::basic_format_args<fmt::v5::wformat_context>::basic_format_args(void)'
2>fmt\core.h(1171,3): message :   basic_format_args() : types_(0) {}
2>fmt\core.h(1171,3): message :   ^ (compiling source file ..\core\typedefs.cpp)
2>fmt\core.h(1219,1): message :  while trying to match the argument list '(fmt::v5::format_args)'
2>fmt\core.h(1219,1): message :       : basic_format_args<wformat_context>(std::forward<Args>(args)...) {}
2>fmt\core.h(1219,1): message : ^ (compiling source file ..\core\typedefs.cpp)

Alternatively if I try to convert into char and then convert out, I can't get it to work for more than one argument:

wstring
fmt_msg2(const wchar_t *msg, fmt::format_args args) {
  std::string s  = utf8_from_utf16(msg).c_str();
  std::string s_ = fmt::vformat(s, args);
  return utf16_from_utf8(s_.data());
}

wstring s = fmt_msg2(L"hey {}", 24); // works
wstring s = fmt_msg2(L"hey {} {}", 24, 58); // error

1>client.cpp
1>client.cpp(757,44): error C2660:  'fmt_msg2': function does not take 3 arguments
1>client.cpp(757,44): error C2660:   wstring s = fmt_msg2(L"hey {} {}", 24, 58);
1>client.cpp(757,44): error C2660:                                            ^
1>typedefs.h(109,9): message :  see declaration of 'fmt_msg2'
1>typedefs.h(109,9): message : wstring fmt_msg2(wchar_t cc *msg, fmt::format_args args);
1>typedefs.h(109,9): message :         ^

I also found mention of a fmt::MemoryWriter which might help me format into a wchar_t[], but it looks like it isn't available anymore?

Not sure what else to try.

update

After looking at it with fresh eyes, I realized that I wasn't wrapping fmt_msg2—and so now I have this:

in the typedefs.h file:

ea::wstring vfmt_msg3(const ea::wstring &msg, fmt::wformat_args args);

template <typename... Args>
ea::wstring
fmt_msg3(const ea::wstring &format, const Args &... args) {
    return vfmt_msg3(format, fmt::make_format_args<fmt::wformat_args>(args...));
}

in the client.cpp file:

ea::wstring
vfmt_msg3(const ea::wstring &msg, fmt::wformat_args args) {
    std::wstring s_ = fmt::vformat(std::wstring(msg.data()), args);
    return ea::wstring(s_.data());
}

wstring s = fmt_msg3(L"hey {} {}", 24, 58);

But on Visual Studio 16.2.0 I get the following error:

core.h(687,39): error C2039:  'char_type': is not a member of 'fmt::v5::wformat_args'
core.h(687,39): error C2039:   using char_type = typename Context::char_type;
core.h(687,39): error C2039:                                       ^ (compiling source file client.cpp)
core.h(1216): message :  see declaration of 'fmt::v5::wformat_args'
core.h(1216): message : struct wformat_args : basic_format_args<wformat_context> { (compiling source file client.cpp)
core.h(1095): message :  see reference to class template instantiation 'fmt::v5::internal::value<Context>' being compiled
core.h(1095): message :         with
core.h(1095): message :         [
core.h(1095): message :             Context=fmt::v5::wformat_args
core.h(1095): message :         ]
core.h(1095): message :   value_type data_[num_args + (!is_packed || num_args == 0 ? 1 : 0)]; (compiling source file client.cpp)
typedefs.h(119): message :  see reference to class template instantiation 'fmt::v5::format_arg_store<fmt::v5::wformat_args,int,int>' being compiled
typedefs.h(119): message : fmt_msg3(const ea::wstring &format, const Args &... args) { (compiling source file client.cpp)
client.cpp(757): message :  see reference to function template instantiation 'eastl::wstring fmt_msg3<int,int>(const eastl::wstring &,const int &,const int &)' being compiled
client.cpp(757): message :   wstring s = fmt_msg3(L"hey {} {}", 24, 58);
Mark Kosyk
  • 115
  • 1
  • 8

1 Answers1

6

It seems that you need to use wformat_args and explicitly specify wformat_context for make_format_args:

void vreport_error2(const wchar_t *format, fmt::wformat_args args)  {
  fmt::print("Error: ");
  fmt::vprint(format, args);
}
template <typename... Args>
void
report_error2(const wchar_t *format, const Args &... args) {
  vreport_error2(format, fmt::make_format_args<fmt::wformat_context>(args...));
}
cpplearner
  • 13,776
  • 2
  • 47
  • 72
  • Using Visual Studio 16.2.0 that code gives me: ```fmt\core.h(687,39): error C2039: 'char_type': is not a member of 'fmt::v5::wformat_args' fmt\core.h(687,39): error C2039: using char_type = typename Context::char_type; fmt\core.h(687,39): error C2039: ^ (compiling source file client.cpp)``` – Mark Kosyk Aug 11 '19 at 18:23
  • char_type is defined in basic_format_context (and therefore in wformat_context): https://github.com/fmtlib/fmt/blob/9f09b8eed11017ac4aba23694de5e94c78bcc381/include/fmt/core.h#L1029 . Make sure to use a recent version of {fmt} and MSVC. – vitaut Aug 12 '19 at 02:32
  • Thanks for the help. I just fetched fmtlib 10 minutes ago, and my Visual Studio 16.2.0 is from July 24, 2019 and I'm still getting the same error. 16.2.1 is out but I don't want to update just on the off-chance that this runs—nothing in the changelog seems pertinent. Either way, I'm not really looking to print—ideally I'd want a wrapped function that builds the format output into an ea::wstring that it can return like what fmt_msg3 is flailing to do. – Mark Kosyk Aug 12 '19 at 03:33
  • 1
    @MarkKosyk Note that you should use fmt::make_format_args, not fmt::make_format_args – cpplearner Aug 12 '19 at 05:46