diff --git a/doc/src/unpack.md b/doc/src/unpack.md index a3cad83..5200eec 100644 --- a/doc/src/unpack.md +++ b/doc/src/unpack.md @@ -40,6 +40,23 @@ Example assert(r == 5); +is_unpackable +============= + +This is a trait that can be used to detect whethet the type can be called +with `unpack`. + +Synopsis +-------- + + template + struct is_unpackable; + +Example +------- + + static_assert(fit::is_unpackable>::value, "Failed"); + unpack_sequence =============== diff --git a/fit/detail/and.h b/fit/detail/and.h new file mode 100644 index 0000000..6399830 --- /dev/null +++ b/fit/detail/and.h @@ -0,0 +1,23 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + and.h + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +==============================================================================*/ + +#ifndef FIT_GUARD_AND_H +#define FIT_GUARD_AND_H + +#include + +namespace fit { namespace detail { + +template struct bool_seq {}; +template +struct and_ +: std::is_same, bool_seq<(Ts::value, true)...>>::type +{}; + +}} + +#endif \ No newline at end of file diff --git a/fit/detail/delegate.h b/fit/detail/delegate.h index c9690ac..8b969fe 100644 --- a/fit/detail/delegate.h +++ b/fit/detail/delegate.h @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -63,12 +64,6 @@ struct enable_if_constructible // static_assert(!std::is_same, std::unique_ptr > >::value, ""); }; -template struct bool_seq {}; -template -struct and_ -: std::is_same, bool_seq<(Ts::value, true)...>>::type -{}; - template struct is_default_constructible_helper : std::false_type diff --git a/fit/unpack.h b/fit/unpack.h index 73eafb4..ef8eea3 100644 --- a/fit/unpack.h +++ b/fit/unpack.h @@ -50,6 +50,23 @@ /// assert(r == 5); /// /// +/// is_unpackable +/// ============= +/// +/// This is a trait that can be used to detect whethet the type can be called +/// with `unpack`. +/// +/// Synopsis +/// -------- +/// +/// template +/// struct is_unpackable; +/// +/// Example +/// ------- +/// +/// static_assert(fit::is_unpackable>::value, "Failed"); +/// /// unpack_sequence /// =============== /// @@ -81,7 +98,10 @@ #include #include #include +#include +#include #include +#include #include #include #include @@ -89,9 +109,24 @@ namespace fit { template -struct unpack_sequence; +struct unpack_sequence +{ + typedef void not_unpackable; +}; + namespace detail { +template +struct is_unpackable_impl +: std::true_type +{}; + +template +struct is_unpackable_impl::not_unpackable +>::type> +: std::false_type +{}; template constexpr auto unpack_impl(F&& f, Sequence&& s) FIT_RETURNS @@ -108,6 +143,13 @@ constexpr auto unpack_join(F&& f, Sequences&&... s) FIT_RETURNS } +template +struct is_unpackable +: detail::is_unpackable_impl< + typename std::remove_cv::type>::type +> +{}; + template struct unpack_adaptor : F { @@ -119,16 +161,63 @@ struct unpack_adaptor : F return always_ref(*this)(xs...); } + struct unpack_failure + { + template + struct apply + { + struct deducer + { + template + typename Failure::template of operator()(Ts&&...) const; + }; + + template::value + )>::type> + static auto deduce(T&& x) + FIT_RETURNS + ( + detail::unpack_impl(deducer(), fit::forward(x)) + ); + + template, is_unpackable... + >::value)>::type> + static auto deduce(T&& x, Ts&&... xs) FIT_RETURNS + ( + detail::unpack_join(deducer(), fit::forward(x), fit::forward(xs)...) + ); + + template + struct of +#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 7 + : std::enable_if()...))>::type +#else + : decltype(apply::deduce(std::declval()...)) +#endif + {}; + }; + }; + + struct failure + : failure_map + {}; + FIT_RETURNS_CLASS(unpack_adaptor); - template + template::value + )>::type> constexpr auto operator()(T&& x) const FIT_RETURNS ( detail::unpack_impl(FIT_MANGLE_CAST(const F&)(FIT_CONST_THIS->base_function(x)), fit::forward(x)) ); - template + template, is_unpackable... + >::value)>::type> constexpr auto operator()(T&& x, Ts&&... xs) const FIT_RETURNS ( detail::unpack_join(FIT_MANGLE_CAST(const F&)(FIT_CONST_THIS->base_function(x)), fit::forward(x), fit::forward(xs)...) diff --git a/test/unpack.cpp b/test/unpack.cpp index e53ce83..bb6f604 100644 --- a/test/unpack.cpp +++ b/test/unpack.cpp @@ -11,59 +11,96 @@ fit::static_ > binary_unpack = {}; FIT_STATIC_AUTO unary_unpack_constexpr = fit::unpack_adaptor(); FIT_STATIC_AUTO binary_unpack_constexpr = fit::unpack_adaptor(); +FIT_STATIC_AUTO unary_unpack_reveal = fit::reveal_adaptor>(); +FIT_STATIC_AUTO binary_unpack_reveal = fit::reveal_adaptor>(); + FIT_TEST_CASE() { FIT_TEST_CHECK(3 == fit::unpack(unary_class())(std::make_tuple(3))); FIT_TEST_CHECK(3 == unary_unpack(std::make_tuple(3))); + FIT_TEST_CHECK(3 == unary_unpack_reveal(std::make_tuple(3))); int ifu = 3; FIT_TEST_CHECK(3 == unary_unpack(std::tuple(ifu))); FIT_STATIC_TEST_CHECK(3 == fit::unpack(unary_class())(std::make_tuple(3))); FIT_STATIC_TEST_CHECK(3 == unary_unpack_constexpr(std::make_tuple(3))); + FIT_STATIC_TEST_CHECK(3 == unary_unpack_reveal(std::make_tuple(3))); } FIT_TEST_CASE() { FIT_TEST_CHECK(3 == fit::unpack(unary_class())(fit::pack_decay(3))); FIT_TEST_CHECK(3 == unary_unpack(fit::pack_decay(3))); + FIT_TEST_CHECK(3 == unary_unpack_reveal(fit::pack_decay(3))); int ifu = 3; FIT_TEST_CHECK(3 == unary_unpack(fit::pack_forward(ifu))); FIT_STATIC_TEST_CHECK(3 == fit::unpack(unary_class())(fit::pack_decay(3))); FIT_STATIC_TEST_CHECK(3 == unary_unpack_constexpr(fit::pack_decay(3))); + FIT_STATIC_TEST_CHECK(3 == unary_unpack_reveal(fit::pack_decay(3))); } FIT_TEST_CASE() { FIT_TEST_CHECK(3 == fit::unpack(binary_class())(std::make_tuple(1, 2))); FIT_TEST_CHECK(3 == binary_unpack(std::make_tuple(1, 2))); + FIT_TEST_CHECK(3 == binary_unpack_reveal(std::make_tuple(1, 2))); FIT_TEST_CHECK(3 == fit::unpack(binary_class())(std::make_tuple(1), std::make_tuple(2))); FIT_TEST_CHECK(3 == binary_unpack(std::make_tuple(1), std::make_tuple(2))); + FIT_TEST_CHECK(3 == binary_unpack_reveal(std::make_tuple(1), std::make_tuple(2))); FIT_TEST_CHECK(3 == fit::unpack(binary_class())(std::make_tuple(1), std::make_tuple(), std::make_tuple(2))); FIT_TEST_CHECK(3 == binary_unpack(std::make_tuple(1), std::make_tuple(), std::make_tuple(2))); + FIT_TEST_CHECK(3 == binary_unpack_reveal(std::make_tuple(1), std::make_tuple(), std::make_tuple(2))); FIT_TEST_CHECK(3 == fit::unpack(binary_class())(std::make_tuple(), std::make_tuple(1), std::make_tuple(), std::make_tuple(2))); FIT_TEST_CHECK(3 == binary_unpack(std::make_tuple(), std::make_tuple(1), std::make_tuple(), std::make_tuple(2))); + FIT_TEST_CHECK(3 == binary_unpack_reveal(std::make_tuple(), std::make_tuple(1), std::make_tuple(), std::make_tuple(2))); FIT_TEST_CHECK(3 == fit::unpack(binary_class())(std::make_tuple(1), std::make_tuple(), std::make_tuple(2), std::make_tuple())); FIT_TEST_CHECK(3 == binary_unpack(std::make_tuple(1), std::make_tuple(), std::make_tuple(2), std::make_tuple())); + FIT_TEST_CHECK(3 == binary_unpack_reveal(std::make_tuple(1), std::make_tuple(), std::make_tuple(2), std::make_tuple())); FIT_STATIC_TEST_CHECK(3 == fit::unpack(binary_class())(std::make_tuple(1, 2))); FIT_STATIC_TEST_CHECK(3 == binary_unpack_constexpr(std::make_tuple(1, 2))); + FIT_STATIC_TEST_CHECK(3 == binary_unpack_reveal(std::make_tuple(1, 2))); FIT_STATIC_TEST_CHECK(3 == fit::unpack(binary_class())(std::make_tuple(1), std::make_tuple(2))); FIT_STATIC_TEST_CHECK(3 == binary_unpack_constexpr(std::make_tuple(1), std::make_tuple(2))); + FIT_STATIC_TEST_CHECK(3 == binary_unpack_reveal(std::make_tuple(1), std::make_tuple(2))); FIT_STATIC_TEST_CHECK(3 == fit::unpack(binary_class())(std::make_tuple(1), std::make_tuple(), std::make_tuple(2))); FIT_STATIC_TEST_CHECK(3 == binary_unpack_constexpr(std::make_tuple(1), std::make_tuple(), std::make_tuple(2))); + FIT_STATIC_TEST_CHECK(3 == binary_unpack_reveal(std::make_tuple(1), std::make_tuple(), std::make_tuple(2))); FIT_STATIC_TEST_CHECK(3 == fit::unpack(binary_class())(std::make_tuple(), std::make_tuple(1), std::make_tuple(), std::make_tuple(2))); FIT_STATIC_TEST_CHECK(3 == binary_unpack_constexpr(std::make_tuple(), std::make_tuple(1), std::make_tuple(), std::make_tuple(2))); + FIT_STATIC_TEST_CHECK(3 == binary_unpack_reveal(std::make_tuple(), std::make_tuple(1), std::make_tuple(), std::make_tuple(2))); FIT_STATIC_TEST_CHECK(3 == fit::unpack(binary_class())(std::make_tuple(1), std::make_tuple(), std::make_tuple(2), std::make_tuple())); FIT_STATIC_TEST_CHECK(3 == binary_unpack_constexpr(std::make_tuple(1), std::make_tuple(), std::make_tuple(2), std::make_tuple())); + FIT_STATIC_TEST_CHECK(3 == binary_unpack_reveal(std::make_tuple(1), std::make_tuple(), std::make_tuple(2), std::make_tuple())); +} + +FIT_TEST_CASE() +{ + auto p1 = fit::pack(1, 2); + static_assert(fit::is_unpackable::value, "Not unpackable"); + static_assert(fit::is_unpackable::value, "Not unpackable"); + + auto p2 = fit::pack_forward(1, 2); + static_assert(fit::is_unpackable::value, "Not unpackable"); + static_assert(fit::is_unpackable::value, "Not unpackable"); + + auto p3 = fit::pack_decay(1, 2); + static_assert(fit::is_unpackable::value, "Not unpackable"); + static_assert(fit::is_unpackable::value, "Not unpackable"); + + static_assert(fit::is_unpackable>::value, "Not unpackable"); + + static_assert(!fit::is_unpackable::value, "Unpackable"); + static_assert(!fit::is_unpackable::value, "Unpackable"); } FIT_STATIC_AUTO lambda_unary_unpack = fit::unpack(FIT_STATIC_LAMBDA(int x)