C++ {fmt} fmt::vformat with wide-string and fmt::make_wformat_args fails to compile

705 Views Asked by At

This code fails to compile. (error: no matching function for call to 'vformat(std::wstring&, fmt::v10::format_arg_store<fmt::v10::basic_format_context<std::back_insert_iterator<fmt::v10::detail::buffer<wchar_t> >, wchar_t>, int>)')

#include <fmt/xchar.h>
#include <string>
#include <iostream>

int main() {
    int arg_1 = 12;
    std::wstring format = L"Hello {}";
    std::wstring test = fmt::vformat(format, fmt::make_wformat_args(arg_1));
    std::wcout << test;
    return 0;
}

However, this code successfully compiles.

#include <fmt/xchar.h>
#include <string>
#include <iostream>

int main() {
    int arg_1 = 12;
    std::string format = "Hello {}";
    std::string test = fmt::vformat(format, fmt::make_format_args(arg_1));
    std::cout << test;
    return 0;
}

I am using {fmt} 10.0.0 and including xchar.h, fmt::format works as I would expect with wide strings, it seems I am facing this problem with only fmt::vformat.

I have tried including various separate fmt header files in different configurations (fmt/core.h, fmt/format.h, fmt/xchar.h). This seems pointless as xchar.h includes the other libraries header files.

While I specifically use MSVC, I have tried and have had the same issue on GCC.

I have tried using fmt::make_format_args instead.

I have also tried specifying the fmt::wformat_context template parameter for fmt::make_wformat_args.

My specific use case has me using localization files from disk, so I cannot know the format strings at compile time.

2

There are 2 best solutions below

0
vitaut On BEST ANSWER

You shouldn't be using fmt::vformat except when writing a formatting function yourself. A proper way to pass a format string only known at runtime is by wrapping it in fmt::runtime and calling fmt::format:

#include <fmt/xchar.h>
#include <iostream>

int main() {
  int arg_1 = 12;
  std::wstring format = L"Hello {}";
  std::wstring test = fmt::format(fmt::runtime(format), arg_1);
  std::wcout << test;
}

https://godbolt.org/z/4WKd575o7

0
Artyer On

vformat's first argument is a string view. Seems like <fmt/xchar.h> adds an overload like:

template<typename Char>
std::basic_string<Char> fmt::vformat(fmt::basic_string_view<Char>, basic_format_args<some_non_deduced_context>);

So Char can't be deduced from std::basic_string<wchar_t>, and you need an actual fmt::basic_string_view:

std::wstring test = fmt::vformat(fmt::wstring_view(format), fmt::make_wformat_args(arg_1));