Search code examples
c++c++20constexprc++-conceptsfmt

Constexpr matching wide vs narrow strings types


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?


Solution

  • 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;
    }