Skip to content

Commit 9e092a6

Browse files
committed
Added formattable concept
1 parent b817610 commit 9e092a6

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

Diff for: include/fmt/base.h

+14
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,15 @@ import std;
149149
# define FMT_USE_NONTYPE_TEMPLATE_ARGS 0
150150
#endif
151151

152+
// Detect C++20 concepts
153+
#ifdef FMT_USE_CONCEPTS
154+
// Use the provided definition.
155+
#elif defined(__cpp_concepts)
156+
# define FMT_USE_CONCEPTS 1
157+
#else
158+
# define FMT_USE_CONCEPTS 0
159+
#endif
160+
152161
// Check if exceptions are disabled.
153162
#ifdef FMT_EXCEPTIONS
154163
// Use the provided definition.
@@ -2007,6 +2016,11 @@ using is_formattable = bool_constant<!std::is_base_of<
20072016
detail::unformattable, decltype(detail::arg_mapper<buffered_context<Char>>()
20082017
.map(std::declval<T&>()))>::value>;
20092018

2019+
#if FMT_USE_CONCEPTS
2020+
template <typename T, typename Char = char>
2021+
concept formattable = is_formattable<remove_reference_t<T>, Char>::value;
2022+
#endif
2023+
20102024
/**
20112025
\rst
20122026
Constructs an object that stores references to arguments and can be implicitly

Diff for: test/base-test.cc

+70
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,64 @@ TEST(core_test, is_formattable) {
687687
static_assert(!fmt::is_formattable<unformattable_scoped_enum>::value, "");
688688
}
689689

690+
#if FMT_USE_CONCEPTS
691+
TEST(core_test, formattable) {
692+
static_assert(fmt::formattable<char>);
693+
static_assert(fmt::formattable<char&>);
694+
static_assert(fmt::formattable<char&&>);
695+
static_assert(fmt::formattable<const char>);
696+
static_assert(fmt::formattable<const char&>);
697+
static_assert(fmt::formattable<const char&&>);
698+
699+
static_assert(fmt::formattable<fmt::basic_string_view<char>>);
700+
static_assert(fmt::formattable<fmt::basic_string_view<char>&>);
701+
static_assert(fmt::formattable<fmt::basic_string_view<char>&&>);
702+
static_assert(fmt::formattable<const fmt::basic_string_view<char>>);
703+
static_assert(fmt::formattable<const fmt::basic_string_view<char>&>);
704+
static_assert(fmt::formattable<const fmt::basic_string_view<char>&&>);
705+
706+
static_assert(!fmt::formattable<wchar_t>);
707+
# ifdef __cpp_char8_t
708+
static_assert(!fmt::formattable<char8_t>);
709+
# endif
710+
static_assert(!fmt::formattable<char16_t>);
711+
static_assert(!fmt::formattable<char32_t>);
712+
static_assert(!fmt::formattable<signed char*>);
713+
static_assert(!fmt::formattable<unsigned char*>);
714+
static_assert(!fmt::formattable<const signed char*>);
715+
static_assert(!fmt::formattable<const unsigned char*>);
716+
static_assert(!fmt::formattable<const wchar_t*>);
717+
static_assert(!fmt::formattable<const wchar_t[3]>);
718+
static_assert(!fmt::formattable<fmt::basic_string_view<wchar_t>>);
719+
static_assert(fmt::formattable<enabled_formatter>);
720+
static_assert(!fmt::formattable<enabled_ptr_formatter*>);
721+
static_assert(!fmt::formattable<disabled_formatter>);
722+
static_assert(!fmt::formattable<disabled_formatter_convertible>);
723+
724+
static_assert(fmt::formattable<const_formattable&>);
725+
static_assert(fmt::formattable<const const_formattable&>);
726+
727+
static_assert(fmt::formattable<nonconst_formattable&>);
728+
# if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
729+
static_assert(!fmt::formattable<const nonconst_formattable&>);
730+
# endif
731+
732+
static_assert(!fmt::formattable<convertible_to_pointer>);
733+
const auto f = convertible_to_pointer_formattable();
734+
auto str = std::string();
735+
fmt::format_to(std::back_inserter(str), "{}", f);
736+
EXPECT_EQ(str, "test");
737+
738+
static_assert(!fmt::formattable<void (*)()>);
739+
740+
struct s;
741+
static_assert(!fmt::formattable<int(s::*)>);
742+
static_assert(!fmt::formattable<int (s::*)()>);
743+
static_assert(!fmt::formattable<unformattable_scoped_enum>);
744+
static_assert(!fmt::formattable<unformattable_scoped_enum>);
745+
}
746+
#endif
747+
690748
TEST(core_test, format_to) {
691749
auto s = std::string();
692750
fmt::format_to(std::back_inserter(s), "{}", 42);
@@ -757,6 +815,9 @@ struct implicitly_convertible_to_string_view {
757815
TEST(core_test, no_implicit_conversion_to_string_view) {
758816
EXPECT_FALSE(
759817
fmt::is_formattable<implicitly_convertible_to_string_view>::value);
818+
#if FMT_USE_CONCEPTS
819+
static_assert(!fmt::formattable<implicitly_convertible_to_string_view>);
820+
#endif
760821
}
761822

762823
#ifdef FMT_USE_STRING_VIEW
@@ -767,6 +828,9 @@ struct implicitly_convertible_to_std_string_view {
767828
TEST(core_test, no_implicit_conversion_to_std_string_view) {
768829
EXPECT_FALSE(
769830
fmt::is_formattable<implicitly_convertible_to_std_string_view>::value);
831+
# if FMT_USE_CONCEPTS
832+
static_assert(!fmt::formattable<implicitly_convertible_to_std_string_view>);
833+
# endif
770834
}
771835
#endif
772836

@@ -781,6 +845,9 @@ TEST(core_test, format_explicitly_convertible_to_string_view) {
781845
// default because it may introduce ODR violations.
782846
static_assert(
783847
!fmt::is_formattable<explicitly_convertible_to_string_view>::value, "");
848+
# if FMT_USE_CONCEPTS
849+
static_assert(!fmt::formattable<explicitly_convertible_to_string_view>);
850+
# endif
784851
}
785852

786853
# ifdef FMT_USE_STRING_VIEW
@@ -794,6 +861,9 @@ TEST(core_test, format_explicitly_convertible_to_std_string_view) {
794861
static_assert(
795862
!fmt::is_formattable<explicitly_convertible_to_std_string_view>::value,
796863
"");
864+
# if FMT_USE_CONCEPTS
865+
static_assert(!fmt::formattable<explicitly_convertible_to_std_string_view>);
866+
# endif
797867
}
798868
# endif
799869
#endif

0 commit comments

Comments
 (0)