Skip to content

Commit 1d8750c

Browse files
committed
Add support for incomplete types
1 parent 77c0fc0 commit 1d8750c

File tree

6 files changed

+60
-7
lines changed

6 files changed

+60
-7
lines changed

include/fmt/base.h

+6-3
Original file line numberDiff line numberDiff line change
@@ -1030,7 +1030,7 @@ enum {
10301030
pointer_set = set(type::pointer_type)
10311031
};
10321032

1033-
struct view {};
1033+
template <typename T> struct is_view : std::false_type {};
10341034

10351035
template <typename Char, typename T> struct named_arg;
10361036
template <typename T> struct is_named_arg : std::false_type {};
@@ -1039,14 +1039,17 @@ template <typename T> struct is_static_named_arg : std::false_type {};
10391039
template <typename Char, typename T>
10401040
struct is_named_arg<named_arg<Char, T>> : std::true_type {};
10411041

1042-
template <typename Char, typename T> struct named_arg : view {
1042+
template <typename Char, typename T> struct named_arg {
10431043
const Char* name;
10441044
const T& value;
10451045

10461046
named_arg(const Char* n, const T& v) : name(n), value(v) {}
10471047
static_assert(!is_named_arg<T>::value, "nested named arguments");
10481048
};
10491049

1050+
template <typename Char, typename T>
1051+
struct is_view<named_arg<Char, T>> : std::true_type {};
1052+
10501053
template <bool B = false> constexpr auto count() -> int { return B ? 1 : 0; }
10511054
template <bool B1, bool B2, bool... Tail> constexpr auto count() -> int {
10521055
return (B1 ? 1 : 0) + count<B2, Tail...>();
@@ -2715,7 +2718,7 @@ template <typename... T> struct fstring {
27152718
template <size_t N>
27162719
FMT_CONSTEVAL FMT_ALWAYS_INLINE fstring(const char (&s)[N]) : str(s, N - 1) {
27172720
using namespace detail;
2718-
static_assert(count<(std::is_base_of<view, remove_reference_t<T>>::value &&
2721+
static_assert(count<(is_view<remove_cvref_t<T>>::value &&
27192722
std::is_reference<T>::value)...>() == 0,
27202723
"passing views as lvalues is disallowed");
27212724
if (FMT_USE_CONSTEVAL) parse_format_string<char>(s, checker(s, arg_pack()));

include/fmt/color.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -468,12 +468,14 @@ template <typename Char> inline void reset_color(buffer<Char>& buffer) {
468468
buffer.append(reset_color.begin(), reset_color.end());
469469
}
470470

471-
template <typename T> struct styled_arg : view {
471+
template <typename T> struct styled_arg {
472472
const T& value;
473473
text_style style;
474474
styled_arg(const T& v, text_style s) : value(v), style(s) {}
475475
};
476476

477+
template <typename T> struct is_view<styled_arg<T>> : std::true_type {};
478+
477479
template <typename Char>
478480
void vformat_to(buffer<Char>& buf, text_style ts, basic_string_view<Char> fmt,
479481
basic_format_args<buffered_context<Char>> args) {

include/fmt/format.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -3554,13 +3554,17 @@ FMT_CONSTEXPR void handle_dynamic_spec(
35543554
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
35553555
template <typename T, typename Char, size_t N,
35563556
fmt::detail::fixed_string<Char, N> Str>
3557-
struct static_named_arg : view {
3557+
struct static_named_arg {
35583558
static constexpr auto name = Str.data;
35593559

35603560
const T& value;
35613561
static_named_arg(const T& v) : value(v) {}
35623562
};
35633563

3564+
template <typename T, typename Char, size_t N,
3565+
fmt::detail::fixed_string<Char, N> Str>
3566+
struct is_view<static_named_arg<T, Char, N, Str>> : std::true_type {};
3567+
35643568
template <typename T, typename Char, size_t N,
35653569
fmt::detail::fixed_string<Char, N> Str>
35663570
struct is_named_arg<static_named_arg<T, Char, N, Str>> : std::true_type {};

include/fmt/ranges.h

+8-2
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ struct formatter<
620620
};
621621

622622
template <typename It, typename Sentinel, typename Char = char>
623-
struct join_view : detail::view {
623+
struct join_view {
624624
It begin;
625625
Sentinel end;
626626
basic_string_view<Char> sep;
@@ -629,6 +629,9 @@ struct join_view : detail::view {
629629
: begin(std::move(b)), end(e), sep(s) {}
630630
};
631631

632+
template <typename It, typename Sentinel, typename Char>
633+
struct detail::is_view<join_view<It, Sentinel, Char>> : std::true_type {};
634+
632635
template <typename It, typename Sentinel, typename Char>
633636
struct formatter<join_view<It, Sentinel, Char>, Char> {
634637
private:
@@ -670,14 +673,17 @@ struct formatter<join_view<It, Sentinel, Char>, Char> {
670673
}
671674
};
672675

673-
template <typename Char, typename Tuple> struct tuple_join_view : detail::view {
676+
template <typename Char, typename Tuple> struct tuple_join_view {
674677
const Tuple& tuple;
675678
basic_string_view<Char> sep;
676679

677680
tuple_join_view(const Tuple& t, basic_string_view<Char> s)
678681
: tuple(t), sep{s} {}
679682
};
680683

684+
template <typename Char, typename Tuple>
685+
struct detail::is_view<tuple_join_view<Char, Tuple>> : std::true_type {};
686+
681687
// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers
682688
// support in tuple_join. It is disabled by default because of issues with
683689
// the dynamic width and precision.

test/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ add_fmt_test(assert-test)
5353
add_fmt_test(chrono-test)
5454
add_fmt_test(color-test)
5555
add_fmt_test(gtest-extra-test)
56+
add_fmt_test(incomplete-type-test)
5657
add_fmt_test(format-test mock-allocator.h)
5758
if (MSVC)
5859
target_compile_options(format-test PRIVATE /bigobj)

test/incomplete-type-test.cc

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Formatting library for C++ - formatting library tests
2+
//
3+
// Copyright (c) 2012 - present, Victor Zverovich
4+
// All rights reserved.
5+
//
6+
// For the license information refer to format.h.
7+
8+
#include "fmt/format.h"
9+
#include "fmt/color.h"
10+
#include "gtest/gtest.h"
11+
12+
// Only defined after all the tests.
13+
struct incomplete_type;
14+
extern const incomplete_type& external_instance;
15+
16+
template <> struct fmt::formatter<incomplete_type> : fmt::formatter<int> {
17+
auto format(const incomplete_type& x, fmt::context& ctx) const
18+
-> decltype(ctx.out());
19+
};
20+
21+
TEST(incomplete_type_test, format) {
22+
EXPECT_EQ(fmt::format("{}", external_instance), fmt::format("{}", 42));
23+
EXPECT_EQ(fmt::format("{:4}", external_instance), fmt::format("{:4}", 42));
24+
EXPECT_EQ(fmt::format("{:4}", fmt::styled(external_instance, fg(fmt::color::red))), fmt::format("{:4}", fmt::styled(42, fg(fmt::color::red))));
25+
}
26+
27+
struct incomplete_type {
28+
int i;
29+
};
30+
31+
const incomplete_type& external_instance{42};
32+
33+
auto fmt::formatter<incomplete_type>::format(const incomplete_type& x,
34+
fmt::context& ctx) const
35+
-> decltype(ctx.out()) {
36+
return fmt::formatter<int>::format(x.i, ctx);
37+
}

0 commit comments

Comments
 (0)