Skip to content

Commit

Permalink
Fix is_formattable for tuple-like types. (#2940)
Browse files Browse the repository at this point in the history
  • Loading branch information
jehelset authored Jun 19, 2022
1 parent f0de128 commit 5682338
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 2 deletions.
34 changes: 33 additions & 1 deletion include/fmt/ranges.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,31 @@ template <size_t N>
using make_index_sequence = make_integer_sequence<size_t, N>;
#endif

template <typename T>
using tuple_index_sequence = make_index_sequence<std::tuple_size<T>::value>;

template <typename T, typename C, bool = is_tuple_like_<T>::value>
class is_tuple_formattable_ {
public:
static constexpr const bool value = false;
};
template <typename T, typename C> class is_tuple_formattable_<T, C, true> {
template <std::size_t... I>
static std::true_type check2(index_sequence<I...>,
integer_sequence<bool, (I == I)...>);
static std::false_type check2(...);
template <std::size_t... I>
static decltype(check2(
index_sequence<I...>{},
integer_sequence<
bool, (is_formattable<typename std::tuple_element<I, T>::type,
C>::value)...>{})) check(index_sequence<I...>);

public:
static constexpr const bool value =
decltype(check(tuple_index_sequence<T>{}))::value;
};

template <class Tuple, class F, size_t... Is>
void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) noexcept {
using std::get;
Expand Down Expand Up @@ -283,8 +308,15 @@ template <typename T> struct is_tuple_like {
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
};

template <typename T, typename C> struct is_tuple_formattable {
static constexpr const bool value =
detail::is_tuple_formattable_<T, C>::value;
};

template <typename TupleT, typename Char>
struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
struct formatter<TupleT, Char,
enable_if_t<fmt::is_tuple_like<TupleT>::value &&
fmt::is_tuple_formattable<TupleT, Char>::value>> {
private:
// C++11 generic lambda for format().
template <typename FormatContext> struct format_each {
Expand Down
12 changes: 11 additions & 1 deletion test/ranges-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,22 @@ TEST(ranges_test, format_pair) {
EXPECT_EQ(fmt::format("{}", p), "(42, 1.5)");
}

struct unformattable {};

TEST(ranges_test, format_tuple) {
auto t =
std::tuple<int, float, std::string, char>(42, 1.5f, "this is tuple", 'i');
EXPECT_EQ(fmt::format("{}", t), "(42, 1.5, \"this is tuple\", 'i')");
EXPECT_EQ(fmt::format("{}", std::tuple<>()), "()");

EXPECT_TRUE((fmt::is_formattable<std::tuple<>>::value));
EXPECT_FALSE((fmt::is_formattable<unformattable>::value));
EXPECT_FALSE((fmt::is_formattable<std::tuple<unformattable>>::value));
EXPECT_FALSE((fmt::is_formattable<std::tuple<unformattable, int>>::value));
EXPECT_FALSE((fmt::is_formattable<std::tuple<int, unformattable>>::value));
EXPECT_FALSE(
(fmt::is_formattable<std::tuple<unformattable, unformattable>>::value));
EXPECT_TRUE((fmt::is_formattable<std::tuple<int, float>>::value));
}

#ifdef FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT
Expand Down Expand Up @@ -220,7 +231,6 @@ TEST(ranges_test, enum_range) {
}

#if !FMT_MSC_VERSION
struct unformattable {};

TEST(ranges_test, unformattable_range) {
EXPECT_FALSE((fmt::has_formatter<std::vector<unformattable>,
Expand Down

0 comments on commit 5682338

Please sign in to comment.