Fix compile time format for ranges, style, and std

This commit is contained in:
j4niwzis 2026-04-29 18:40:34 +10:00
parent eeff8680ed
commit be3ae4ed5d
5 changed files with 47 additions and 26 deletions

View File

@ -471,7 +471,7 @@ template <typename Char> inline void reset_color(buffer<Char>& buffer) {
template <typename T> struct styled_arg : view {
const T& value;
text_style style;
styled_arg(const T& v, text_style s) : value(v), style(s) {}
FMT_CONSTEXPR styled_arg(const T& v, text_style s) : value(v), style(s) {}
};
template <typename Char>
@ -583,8 +583,8 @@ inline auto format_to(OutputIt out, text_style ts, format_string<T...> fmt,
template <typename T, typename Char>
struct formatter<detail::styled_arg<T>, Char> : formatter<T, Char> {
template <typename FormatContext>
auto format(const detail::styled_arg<T>& arg, FormatContext& ctx) const
-> decltype(ctx.out()) {
FMT_CONSTEXPR auto format(const detail::styled_arg<T>& arg,
FormatContext& ctx) const -> decltype(ctx.out()) {
const auto& ts = arg.style;
auto out = ctx.out();

View File

@ -3888,7 +3888,7 @@ template <typename OutputIt, typename Char> class generic_context {
constexpr auto out() const -> iterator { return out_; }
void advance_to(iterator it) {
constexpr void advance_to(iterator it) {
if (!detail::is_back_insert_iterator<iterator>()) out_ = it;
}

View File

@ -69,11 +69,12 @@ struct has_member_fn_begin_end_t<T, void_t<decltype(*std::declval<T>().begin()),
// Member function overloads.
template <typename T>
auto range_begin(T&& rng) -> decltype(static_cast<T&&>(rng).begin()) {
FMT_CONSTEXPR auto range_begin(T&& rng)
-> decltype(static_cast<T&&>(rng).begin()) {
return static_cast<T&&>(rng).begin();
}
template <typename T>
auto range_end(T&& rng) -> decltype(static_cast<T&&>(rng).end()) {
FMT_CONSTEXPR auto range_end(T&& rng) -> decltype(static_cast<T&&>(rng).end()) {
return static_cast<T&&>(rng).end();
}
@ -460,7 +461,8 @@ struct range_formatter<
}
template <typename R, typename FormatContext>
auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) {
FMT_CONSTEXPR auto format(R&& range, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
auto it = detail::range_begin(range);
auto end = detail::range_end(range);
@ -516,7 +518,7 @@ struct formatter<
}
template <typename FormatContext>
auto format(range_type& range, FormatContext& ctx) const
FMT_CONSTEXPR auto format(range_type& range, FormatContext& ctx) const
-> decltype(ctx.out()) {
return range_formatter_.format(range, ctx);
}
@ -625,7 +627,7 @@ struct join_view : detail::view {
Sentinel end;
basic_string_view<Char> sep;
join_view(It b, Sentinel e, basic_string_view<Char> s)
FMT_CONSTEXPR join_view(It b, Sentinel e, basic_string_view<Char> s)
: begin(std::move(b)), end(e), sep(s) {}
};
@ -652,7 +654,8 @@ struct formatter<join_view<It, Sentinel, Char>, Char> {
}
template <typename FormatContext>
auto format(view& value, FormatContext& ctx) const -> decltype(ctx.out()) {
FMT_CONSTEXPR auto format(view& value, FormatContext& ctx) const
-> decltype(ctx.out()) {
using iter =
conditional_t<std::is_copy_constructible<view>::value, It, It&>;
iter it = value.begin;
@ -675,7 +678,7 @@ template <typename Tuple, typename Char> struct tuple_join_view : detail::view {
const Tuple& tuple;
basic_string_view<Char> sep;
tuple_join_view(const Tuple& t, basic_string_view<Char> s)
FMT_CONSTEXPR tuple_join_view(const Tuple& t, basic_string_view<Char> s)
: tuple(t), sep{s} {}
};
@ -694,8 +697,9 @@ struct formatter<tuple_join_view<Tuple, Char>, Char,
}
template <typename FormatContext>
auto format(const tuple_join_view<Tuple, Char>& value,
FormatContext& ctx) const -> typename FormatContext::iterator {
FMT_CONSTEXPR auto format(const tuple_join_view<Tuple, Char>& value,
FormatContext& ctx) const ->
typename FormatContext::iterator {
return do_format(value, ctx, std::tuple_size<Tuple>());
}
@ -726,15 +730,17 @@ struct formatter<tuple_join_view<Tuple, Char>, Char,
}
template <typename FormatContext>
auto do_format(const tuple_join_view<Tuple, Char>&, FormatContext& ctx,
std::integral_constant<size_t, 0>) const ->
FMT_CONSTEXPR auto do_format(const tuple_join_view<Tuple, Char>&,
FormatContext& ctx,
std::integral_constant<size_t, 0>) const ->
typename FormatContext::iterator {
return ctx.out();
}
template <typename FormatContext, size_t N>
auto do_format(const tuple_join_view<Tuple, Char>& value, FormatContext& ctx,
std::integral_constant<size_t, N>) const ->
FMT_CONSTEXPR auto do_format(const tuple_join_view<Tuple, Char>& value,
FormatContext& ctx,
std::integral_constant<size_t, N>) const ->
typename FormatContext::iterator {
using std::get;
auto out =
@ -813,7 +819,7 @@ auto join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel> {
* // Output: 01, 02, 03
*/
template <typename Range, FMT_ENABLE_IF(!is_tuple_like<Range>::value)>
auto join(Range&& r, string_view sep)
FMT_CONSTEXPR auto join(Range&& r, string_view sep)
-> join_view<decltype(detail::range_begin(r)),
decltype(detail::range_end(r))> {
return {detail::range_begin(r), detail::range_end(r), sep};

View File

@ -133,8 +133,8 @@ void write_escaped_path(basic_memory_buffer<Char>& quoted,
#if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT
template <typename Char, typename OutputIt, typename T, typename FormatContext>
auto write_escaped_alternative(OutputIt out, const T& v, FormatContext& ctx)
-> OutputIt {
FMT_CONSTEXPR auto write_escaped_alternative(OutputIt out, const T& v,
FormatContext& ctx) -> OutputIt {
if constexpr (has_to_string_view<T>::value)
return write_escaped_string<Char>(out, detail::to_string_view(v));
if constexpr (std::is_same_v<T, Char>) return write_escaped_char(out, v);
@ -508,7 +508,7 @@ template <typename Char> struct formatter<std::monostate, Char> {
}
template <typename FormatContext>
auto format(const std::monostate&, FormatContext& ctx) const
FMT_CONSTEXPR auto format(const std::monostate&, FormatContext& ctx) const
-> decltype(ctx.out()) {
return detail::write<Char>(ctx.out(), "monostate");
}
@ -524,7 +524,7 @@ struct formatter<Variant, Char,
}
template <typename FormatContext>
auto format(const Variant& value, FormatContext& ctx) const
FMT_CONSTEXPR20 auto format(const Variant& value, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
@ -635,7 +635,7 @@ struct formatter<
}
template <typename Context>
auto format(const std::exception& ex, Context& ctx) const
FMT_CONSTEXPR auto format(const std::exception& ex, Context& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
#if FMT_USE_RTTI
@ -690,11 +690,12 @@ struct formatter<BitRef, Char,
#ifdef __cpp_lib_byte
template <typename Char>
struct formatter<std::byte, Char> : formatter<unsigned, Char> {
static auto format_as(std::byte b) -> unsigned char {
FMT_CONSTEXPR static auto format_as(std::byte b) -> unsigned char {
return static_cast<unsigned char>(b);
}
template <typename Context>
auto format(std::byte b, Context& ctx) const -> decltype(ctx.out()) {
FMT_CONSTEXPR auto format(std::byte b, Context& ctx) const
-> decltype(ctx.out()) {
return formatter<unsigned, Char>::format(format_as(b), ctx);
}
};

View File

@ -13,7 +13,9 @@
#include <vector>
#include "fmt/chrono.h"
#include "fmt/color.h"
#include "fmt/ranges.h"
#include "fmt/std.h"
#include "gmock/gmock.h"
#include "gtest-extra.h"
@ -87,7 +89,6 @@ TEST(compile_test, format_escape) {
EXPECT_EQ("\"abc\" ", fmt::format(FMT_COMPILE("{0:<7?}"), "abc"));
}
TEST(compile_test, format_specs) {
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{:x}"), 0x42));
EXPECT_EQ("1.2 ms ",
@ -224,6 +225,19 @@ TEST(compile_test, constexpr_formatted_size) {
FMT_CONSTEXPR20 size_t str_size =
fmt::formatted_size(FMT_COMPILE("{:s}"), "abc");
EXPECT_EQ(str_size, 3);
FMT_CONSTEXPR20 size_t tuple_size = fmt::formatted_size(
FMT_COMPILE("{}"), fmt::join(std::tuple(1, 2, 3), ","));
EXPECT_EQ(tuple_size, 5);
FMT_CONSTEXPR20 size_t array_size = fmt::formatted_size(
FMT_COMPILE("{}"), fmt::join(std::array{1, 2, 3}, ","));
EXPECT_EQ(array_size, 5);
FMT_CONSTEXPR20 size_t styled_size = fmt::formatted_size(
FMT_COMPILE("{}"),
fmt::styled(std::array{1, 2, 3}, fmt::bg(fmt::color::green)));
EXPECT_EQ(styled_size, 32);
FMT_CONSTEXPR20 size_t variant_size = fmt::formatted_size(
FMT_COMPILE("{}"), std::variant<std::monostate, char>{});
EXPECT_EQ(variant_size, 18);
}
TEST(compile_test, static_format) {