#4991

Fix wide formatting of variant, monostate and expected

OpenINo-xiouswants to merge intofrom

Formatting std::variant, std::monostate, std::expected or std::unexpected into a wide string fails to compile, although fmt::is_formattable<T, wchar_t> is true for these types:

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

static_assert(fmt::is_formattable<std::variant<int>, wchar_t>::value, "");
auto a = fmt::format(L"{}", std::monostate{});
auto b = fmt::format(L"{}", std::variant<int, std::wstring>(L"v"));
auto c = fmt::format(L"{}", std::expected<int, int>(1));  // C++23
auto d = fmt::format(L"{}", std::unexpected<int>(1));     // C++23
include/fmt/std.h:484:31: error: call of overloaded 'write<wchar_t>(..., const char [10])' is ambiguous

The formatters write narrow string literals ("variant(", "monostate", "valueless by exception", "expected(", "unexpected(") with detail::write<Char>, which has no unambiguous overload for Char = wchar_t. This changes them to detail::string_literal<Char, ...> members, the same way the std::optional formatter already handles "optional(" and "none". Narrow output is unchanged.

Tests: added std_test_xchar.variant and std_test_xchar.expected to test/xchar-test.cc, guarded by __cpp_lib_variant / __cpp_lib_expected like the corresponding tests in std-test.cc. Without the change xchar-test.cc does not compile (the errors above, at all six call sites under C++23). With it, the full ctest suite passes with g++ 13 in C++17 (FMT_PEDANTIC=ON, FMT_WERROR=ON), xchar-test and std-test pass in C++23 (where the expected test is compiled) and C++11, and clang-format 21 reports no changes.

Activity

2
vitautrequested changes6d ago
vitaut6d ago

Thanks for the PR. In the std::bad_variant_access catch block, the result of detail::write should be assigned back to out. This is a pre-existing issue, but we might as well fix it here.