Skip to content

Commit 0203853

Browse files
committed
Fix is_formattable for tuple-like types.
1 parent eaa8efb commit 0203853

File tree

3 files changed

+39
-1
lines changed

3 files changed

+39
-1
lines changed

include/fmt/ranges.h

+25-1
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,24 @@ template <size_t N>
202202
using make_index_sequence = make_integer_sequence<size_t, N>;
203203
#endif
204204

205+
template <typename T>
206+
using tuple_index_sequence = make_index_sequence<std::tuple_size_v<T>>;
207+
208+
template <typename T, bool = is_tuple_like_<T>::value>
209+
struct is_tuple_formattable_ {
210+
static constexpr const bool value = false;
211+
};
212+
template <typename T> struct is_tuple_formattable_<T, true> {
213+
template <std::size_t... I>
214+
static std::integral_constant<
215+
bool, (fmt::is_formattable<std::tuple_element_t<I, T>>::value && ...)>
216+
check(index_sequence<I...>);
217+
218+
public:
219+
static constexpr const bool value =
220+
decltype(check(tuple_index_sequence<T>{}))::value;
221+
};
222+
205223
template <class Tuple, class F, size_t... Is>
206224
void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) noexcept {
207225
using std::get;
@@ -283,8 +301,14 @@ template <typename T> struct is_tuple_like {
283301
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
284302
};
285303

304+
template <typename T> struct is_tuple_formattable {
305+
static constexpr const bool value = detail::is_tuple_formattable_<T>::value;
306+
};
307+
286308
template <typename TupleT, typename Char>
287-
struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
309+
struct formatter<TupleT, Char,
310+
enable_if_t<fmt::is_tuple_like<TupleT>::value &&
311+
fmt::is_tuple_formattable<TupleT>::value>> {
288312
private:
289313
// C++11 generic lambda for format().
290314
template <typename FormatContext> struct format_each {

test/ranges-test.cc

+12
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,18 @@ TEST(ranges_test, format_tuple) {
9090
std::tuple<int, float, std::string, char>(42, 1.5f, "this is tuple", 'i');
9191
EXPECT_EQ(fmt::format("{}", t), "(42, 1.5, \"this is tuple\", 'i')");
9292
EXPECT_EQ(fmt::format("{}", std::tuple<>()), "()");
93+
94+
enum class noformatenum{b};
95+
struct noformatstruct{};
96+
EXPECT_TRUE((fmt::is_formattable<std::tuple<>>::value));
97+
EXPECT_FALSE((fmt::is_formattable<noformatenum>::value));
98+
EXPECT_FALSE((fmt::is_formattable<noformatstruct>::value));
99+
EXPECT_FALSE((fmt::is_formattable<std::tuple<noformatenum>>::value));
100+
EXPECT_FALSE((fmt::is_formattable<std::tuple<noformatstruct>>::value));
101+
EXPECT_FALSE((fmt::is_formattable<std::tuple<noformatstruct,int>>::value));
102+
EXPECT_FALSE((fmt::is_formattable<std::tuple<int,noformatenum>>::value));
103+
EXPECT_FALSE((fmt::is_formattable<std::tuple<noformatstruct,noformatenum>>::value));
104+
EXPECT_TRUE((fmt::is_formattable<std::tuple<int,float>>::value));
93105
}
94106

95107
#ifdef FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT

test/xchar-test.cc

+2
Original file line numberDiff line numberDiff line change
@@ -315,10 +315,12 @@ TEST(xchar_test, ostream) {
315315
#endif
316316
}
317317

318+
#ifdef FMT_XCHAR_TEST_ENABLE_FORMAT_MAP
318319
TEST(xchar_test, format_map) {
319320
auto m = std::map<std::wstring, int>{{L"one", 1}, {L"t\"wo", 2}};
320321
EXPECT_EQ(fmt::format(L"{}", m), L"{\"one\": 1, \"t\\\"wo\": 2}");
321322
}
323+
#endif
322324

323325
TEST(xchar_test, escape_string) {
324326
using vec = std::vector<std::wstring>;

0 commit comments

Comments
 (0)