diff --git a/include/fmt/core.h b/include/fmt/core.h index 744d2ab8..62ab7867 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -979,16 +979,22 @@ struct arg_data<T, Char, NUM_ARGS, 0> { template <typename Char> inline void init_named_args(named_arg_info<Char>*, int, int) {} -template <typename Char, typename T, typename... Tail> +template <typename T> struct is_named_arg : std::false_type {}; + +template <typename T, typename Char> +struct is_named_arg<named_arg<Char, T>> : std::true_type {}; + +template <typename Char, typename T, typename... Tail, + FMT_ENABLE_IF(!is_named_arg<T>::value)> void init_named_args(named_arg_info<Char>* named_args, int arg_count, int named_arg_count, const T&, const Tail&... args) { init_named_args(named_args, arg_count + 1, named_arg_count, args...); } -template <typename Char, typename T, typename... Tail> +template <typename Char, typename T, typename... Tail, + FMT_ENABLE_IF(is_named_arg<T>::value)> void init_named_args(named_arg_info<Char>* named_args, int arg_count, - int named_arg_count, const named_arg<Char, T>& arg, - const Tail&... args) { + int named_arg_count, const T& arg, const Tail&... args) { named_args[named_arg_count++] = {arg.name, arg_count}; init_named_args(named_args, arg_count + 1, named_arg_count, args...); } @@ -997,11 +1003,6 @@ template <typename... Args> FMT_CONSTEXPR FMT_INLINE void init_named_args(std::nullptr_t, int, int, const Args&...) {} -template <typename T> struct is_named_arg : std::false_type {}; - -template <typename T, typename Char> -struct is_named_arg<named_arg<Char, T>> : std::true_type {}; - template <bool B = false> constexpr size_t count() { return B ? 1 : 0; } template <bool B1, bool B2, bool... Tail> constexpr size_t count() { return (B1 ? 1 : 0) + count<B2, Tail...>(); @@ -1277,10 +1278,10 @@ template <typename Context> struct arg_mapper { return val; } - template <typename T> - FMT_CONSTEXPR FMT_INLINE auto map(const named_arg<char_type, T>& val) - -> decltype(std::declval<arg_mapper>().map(val.value)) { - return map(val.value); + template <typename T, FMT_ENABLE_IF(is_named_arg<T>::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T& named_arg) + -> decltype(std::declval<arg_mapper>().map(named_arg.value)) { + return map(named_arg.value); } unformattable map(...) { return {}; } diff --git a/include/fmt/format.h b/include/fmt/format.h index be079b66..8b1e8cb6 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3941,6 +3941,24 @@ template <typename Char> struct udl_formatter { } }; +# if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +template <typename T, typename Char, size_t N, fixed_string<Char, N> Str> +struct statically_named_arg : view { + static constexpr auto name = Str.data; + + const T& value; + statically_named_arg(const T& v) : value(v) {} +}; + +template <typename T, typename Char, size_t N, fixed_string<Char, N> Str> +struct is_named_arg<statically_named_arg<T, Char, N, Str>> : std::true_type {}; + +template <typename Char, size_t N, fixed_string<Char, N> Str> struct udl_arg { + template <typename T> auto operator=(T&& value) const { + return statically_named_arg<T, Char, N, Str>(std::forward<T>(value)); + } +}; +# else template <typename Char> struct udl_arg { const Char* str; @@ -3948,6 +3966,7 @@ template <typename Char> struct udl_arg { return {str, std::forward<T>(value)}; } }; +# endif } // namespace detail FMT_MODULE_EXPORT_BEGIN @@ -3981,12 +4000,21 @@ constexpr detail::udl_formatter<wchar_t> operator"" _format(const wchar_t* s, fmt::print("Elapsed time: {s:.2f} seconds", "s"_a=1.23); \endrst */ +# if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +template <detail::fixed_string Str> +constexpr detail::udl_arg<remove_cvref_t<decltype(Str.data[0])>, + sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str> +operator""_a() { + return {}; +} +# else constexpr detail::udl_arg<char> operator"" _a(const char* s, size_t) { return {s}; } constexpr detail::udl_arg<wchar_t> operator"" _a(const wchar_t* s, size_t) { return {s}; } +# endif } // namespace literals FMT_MODULE_EXPORT_END