I have a wrapper around fmt that prints to visual studio debug output. I tried to add wide string support:
template <typename Arg, typename... Args>
void fmt(Arg&& arg, Args&&... args)
{
auto out = fmt::format(arg, args...);
if constexpr (std::is_same<Arg, char8_t*>)
OutputDebugStringA(out.c_str());
else if constexpr (std::is_same<Arg, char16_t*>)
OutputDebugStringW(out.c_str());
else
static_assert(false);
}
But it seems are a lot of different types you might want to match together
const char (&)[N]
, const char*
, char*
etc.
How do you handle this elegantly?
if constexpr
and static_assert
don't work that well together (until C++23).
This example is a C++17 version with SFINAE (for C++20 use concepts).
#include <iostream>
#include <string>
#include <string_view>
#include <type_traits>
#include <fmt/format.h>
#include <fmt/xchar.h>
// static_assert and `constexpr if` don't match, you will always get static_asset failure
// (up to C++20)
template<typename type_t, typename... args_t>
auto my_fmt(type_t&& fmt, args_t&&... args) -> std::enable_if_t<std::is_constructible_v<std::string_view, type_t>, std::string>
{
// for runtime format strings use vformat and make_format_args
auto output = fmt::vformat(std::string_view{ fmt }, fmt::make_format_args(args...));
return output;
}
template<typename type_t, typename... args_t>
auto my_fmt(type_t&& fmt, args_t&&... args) -> std::enable_if_t<std::is_constructible_v<fmt::v10::wstring_view, type_t>, std::wstring>
{
std::wstring output = fmt::vformat(fmt::v10::wstring_view{ fmt }, fmt::make_wformat_args(args...));
return output;
}
int main()
{
std::cout << " char : " << my_fmt("{}", 42) << "\n";
std::wcout << " wchar_t : " << my_fmt(L"{}", 42) << "\n";
return 0;
}