diff --git a/include/mettle/detail/any_capture.hpp b/include/mettle/detail/any_capture.hpp index da19621d..c92f6e46 100644 --- a/include/mettle/detail/any_capture.hpp +++ b/include/mettle/detail/any_capture.hpp @@ -7,27 +7,22 @@ namespace mettle::detail { - template - class any_capture { - public: - using type = T; + struct any_capture_tag {}; - constexpr any_capture(const T &t) : value(t) {} - constexpr any_capture(T &&t) : value(std::move(t)) {} - - T value; - }; + template + class capture_array; template - class any_capture>> { + class capture_array>> + : public any_capture_tag { public: using type = T[N]; - constexpr any_capture(const T (&t)[N]) { + constexpr capture_array(const T (&t)[N]) { for(std::size_t i = 0; i != N; i++) value[i] = t[i]; } - constexpr any_capture(T (&&t)[N]) { + constexpr capture_array(T (&&t)[N]) { for(std::size_t i = 0; i != N; i++) value[i] = std::move(t[i]); } @@ -42,23 +37,24 @@ namespace mettle::detail { #endif template - class any_capture>> { + class capture_array>> + : public any_capture_tag { public: using type = T[N]; - constexpr any_capture(const T (&t)[N]) - : any_capture(t, std::make_index_sequence()) {} - constexpr any_capture(T (&&t)[N]) - : any_capture(std::move(t), std::make_index_sequence()) {} + constexpr capture_array(const T (&t)[N]) + : capture_array(t, std::make_index_sequence()) {} + constexpr capture_array(T (&&t)[N]) + : capture_array(std::move(t), std::make_index_sequence()) {} T value[N]; private: template - constexpr any_capture(const T (&t)[N], std::index_sequence) + constexpr capture_array(const T (&t)[N], std::index_sequence) : value{t[I]...} {} template - constexpr any_capture(T (&&t)[N], std::index_sequence) + constexpr capture_array(T (&&t)[N], std::index_sequence) : value{std::move(t[I])...} {} }; @@ -66,17 +62,37 @@ namespace mettle::detail { # pragma warning(pop) #endif - template - class any_capture : public any_capture { - using any_capture::any_capture; - }; - template - class any_capture { + class capture_array : public any_capture_tag { static_assert(std::is_same::value, "any_capture can't be used by incomplete array types"); }; + template + struct any_capture_type { + using type = T; + }; + template + struct any_capture_type::type>> { + using type = capture_array; + }; + template + struct any_capture_type { + using type = Ret(*)(Args...); + }; + + template + using any_capture = typename any_capture_type::type; + + template + decltype(auto) unwrap_capture(T &&t) { + using V = std::remove_reference_t>; + if constexpr(std::is_base_of_v) + return (t.value); + else + return std::forward(t); + } + } // namespace mettle::detail #endif diff --git a/include/mettle/matchers/collection.hpp b/include/mettle/matchers/collection.hpp index 0aed8bdd..0f53977d 100644 --- a/include/mettle/matchers/collection.hpp +++ b/include/mettle/matchers/collection.hpp @@ -290,13 +290,13 @@ namespace mettle { using std::begin, std::end; return std::is_permutation( begin(actual), end(actual), - begin(container_.value), end(container_.value) + begin(unwrap_capture(container_)), end(unwrap_capture(container_)) ); } std::string desc() const { std::ostringstream ss; - ss << "permutation of " << to_printable(container_.value); + ss << "permutation of " << to_printable(unwrap_capture(container_)); return ss.str(); } private: @@ -314,15 +314,15 @@ namespace mettle { using std::begin, std::end; return std::is_permutation( begin(actual), end(actual), - begin(container_.value), end(container_.value), + begin(unwrap_capture(container_)), end(unwrap_capture(container_)), predicate_ ); } std::string desc() const { std::ostringstream ss; - ss << "permutation of " << to_printable(container_.value) << " for " - << to_printable(predicate_); + ss << "permutation of " << to_printable(unwrap_capture(container_)) + << " for " << to_printable(predicate_); return ss.str(); } private: diff --git a/include/mettle/matchers/core.hpp b/include/mettle/matchers/core.hpp index 4c1cf890..ca603f39 100644 --- a/include/mettle/matchers/core.hpp +++ b/include/mettle/matchers/core.hpp @@ -43,12 +43,13 @@ namespace mettle { template decltype(auto) operator ()(U &&actual) const { - return f_(std::forward(actual), thing_.value); + return f_(std::forward(actual), detail::unwrap_capture(thing_)); } std::string desc() const { std::ostringstream ss; - ss << prefix_ << detail::matcher_desc(thing_.value) << suffix_; + ss << prefix_ << detail::matcher_desc(detail::unwrap_capture(thing_)) + << suffix_; return ss.str(); } private: @@ -95,7 +96,7 @@ namespace mettle { } template - inline auto ensure_matcher(T &&t) { + inline decltype(auto) ensure_matcher(T &&t) { if constexpr(is_matcher_v) { return std::forward(t); } else { diff --git a/include/mettle/matchers/relational.hpp b/include/mettle/matchers/relational.hpp index 5473c12e..61b79a30 100644 --- a/include/mettle/matchers/relational.hpp +++ b/include/mettle/matchers/relational.hpp @@ -50,25 +50,28 @@ namespace mettle { template bool operator ()(U &&actual) const { + using detail::unwrap_capture; if (left_open()) { - if (actual <= low_.value) return false; + if (actual <= unwrap_capture(low_)) return false; } else { - if (actual < low_.value) return false; + if (actual < unwrap_capture(low_)) return false; } if (right_open()) { - if (actual >= high_.value) return false; + if (actual >= unwrap_capture(high_)) return false; } else { - if (actual > high_.value) return false; + if (actual > unwrap_capture(high_)) return false; } return true; } std::string desc() const { + using detail::unwrap_capture; std::ostringstream ss; - ss << "in " << (left_open() ? "(" : "[") << to_printable(low_.value) - << " .. " << to_printable(high_.value) << (right_open() ? ")" : "]"); + ss << "in " << (left_open() ? "(" : "[") + << to_printable(unwrap_capture(low_)) << " .. " + << to_printable(unwrap_capture(high_)) << (right_open() ? ")" : "]"); return ss.str(); } private: diff --git a/include/mettle/suite/factory.hpp b/include/mettle/suite/factory.hpp index 77b39009..f4e3ecdb 100644 --- a/include/mettle/suite/factory.hpp +++ b/include/mettle/suite/factory.hpp @@ -45,7 +45,7 @@ namespace mettle { private: template T make_impl(std::index_sequence) const { - return T(std::get(args_).value...); + return T(detail::unwrap_capture(std::get(args_))...); } tuple_type args_; diff --git a/test/test_any_capture.cpp b/test/test_any_capture.cpp index 58698e78..c29d6ae6 100644 --- a/test/test_any_capture.cpp +++ b/test/test_any_capture.cpp @@ -6,57 +6,60 @@ using namespace mettle; void func() {} suite<> test_capture("any_capture", [](auto &_) { + using detail::any_capture; + using detail::unwrap_capture; + _.test("capture int", []() { - detail::any_capture capture1(1); - expect(capture1.value, equal_to(1)); + any_capture capture1(1); + expect(unwrap_capture(capture1), equal_to(1)); int i = 2; - detail::any_capture capture2(i); - expect(capture2.value, equal_to(i)); + any_capture capture2(i); + expect(unwrap_capture(capture2), equal_to(i)); }); _.test("capture std::string", []() { - detail::any_capture capture1("foo"); - expect(capture1.value, equal_to("foo")); + any_capture capture1("foo"); + expect(unwrap_capture(capture1), equal_to("foo")); std::string s = "bar"; - detail::any_capture capture2(s); - expect(capture2.value, equal_to(s)); + any_capture capture2(s); + expect(unwrap_capture(capture2), equal_to(s)); }); _.test("capture char[]", []() { char s[] = "foo"; - detail::any_capture capture(s); - expect(capture.value, equal_to(std::string("foo"))); + any_capture capture(s); + expect(unwrap_capture(capture), equal_to(std::string("foo"))); }); _.test("capture function", []() { - detail::any_capture capture(func); + any_capture capture(func); - expect(capture.value, equal_to(func)); - expect(capture.value, equal_to(&func)); + expect(unwrap_capture(capture), equal_to(func)); + expect(unwrap_capture(capture), equal_to(&func)); }); _.test("capture by copy", []() { copyable_type t; - detail::any_capture capture(t); + any_capture capture(t); - expect("number of copies", capture.value.copies, equal_to(1)); + expect("number of copies", unwrap_capture(capture).copies, equal_to(1)); }); _.test("capture by move", []() { moveable_type t; - detail::any_capture capture(std::move(t)); + any_capture capture(std::move(t)); - expect("number of copies", capture.value.copies, equal_to(0)); - expect("number of moves", capture.value.moves, equal_to(1)); + expect("number of copies", unwrap_capture(capture).copies, equal_to(0)); + expect("number of moves", unwrap_capture(capture).moves, equal_to(1)); }); _.test("capture array by copy", []() { copyable_type t[2]; - detail::any_capture capture(t); + any_capture capture(t); - expect("number of copies", capture.value, each( + expect("number of copies", unwrap_capture(capture), each( filter([](auto &&x) { return x.copies; }, equal_to(1)) )); }); @@ -68,12 +71,12 @@ suite<> test_capture("any_capture", [](auto &_) { _.test("capture array by move", move_arr_attrs, []() { moveable_type t[2]; - detail::any_capture capture(std::move(t)); + any_capture capture(std::move(t)); - expect("number of copies", capture.value, each( + expect("number of copies", unwrap_capture(capture), each( filter([](auto &&x) { return x.copies; }, equal_to(0)) )); - expect("number of moves", capture.value, each( + expect("number of moves", unwrap_capture(capture), each( filter([](auto &&x) { return x.moves; }, equal_to(1)) )); });