diff --git a/src/detail/arg_fmt.hpp b/src/detail/arg_fmt.hpp index 43a2b26..3dc94ef 100644 --- a/src/detail/arg_fmt.hpp +++ b/src/detail/arg_fmt.hpp @@ -1,6 +1,7 @@ #pragma once #include "src/detail/is_range.hpp" +#include "src/detail/is_specialization_of.hpp" #include "src/detail/priority.hpp" #include "src/detail/type_name.hpp" #include "src/rope.hpp" @@ -38,9 +39,16 @@ class arg_fmt_fn } template < - class... Ts, - std::enable_if_t>, bool> = true> - static constexpr auto impl(priority<2>, const std::tuple& arg) + class T, + std::enable_if_t< + is_specialization_of_v and not is_ostreamable_v, + bool> = true> + static constexpr auto impl(priority<2>, const T& arg) + { + return tuple_impl(arg); + } + template + static constexpr auto tuple_impl(const std::tuple& arg) { return tuple_fmt{arg}; } diff --git a/test/BUILD.bazel b/test/BUILD.bazel index 5f6f152..2a50b50 100644 --- a/test/BUILD.bazel +++ b/test/BUILD.bazel @@ -130,6 +130,7 @@ skytest_test( stdout = [ "empty(\\[1, 2, 3\\])", "empty({4}{5})", + "custom_tuple != custom_tuple", "wrapped{...} == wrapped{...}", ], ) diff --git a/test/arg_fmt_test.cpp b/test/arg_fmt_test.cpp index 8f8c96a..023ecea 100644 --- a/test/arg_fmt_test.cpp +++ b/test/arg_fmt_test.cpp @@ -27,6 +27,16 @@ struct array : std::array } }; +template +struct custom_tuple : std::tuple +{ + friend auto& operator<<(std::ostream& os, const custom_tuple&) + { + os << "custom_tuple"; + return os; + } +}; + struct wrapped { int value; @@ -39,6 +49,7 @@ auto main() -> int using namespace ::skytest::literals; using ::skytest::eq; using ::skytest::expect; + using ::skytest::ne; "array uses default range arg fmt"_test = [] { return expect(empty(std::array{1, 2, 3})); @@ -48,6 +59,10 @@ auto main() -> int return expect(empty(array{4, 5})); }; + "custom tuple uses custom fmt"_test = [] { + return expect(ne(custom_tuple{}, custom_tuple{})); + }; + "type without operator<< is displayed"_test = [] { return expect(eq(wrapped{1}, wrapped{2})); };