diff --git a/README.md b/README.md index 32d3ac0..ae1d996 100644 --- a/README.md +++ b/README.md @@ -34,18 +34,26 @@ ### `invoke_hpp::invoke(F&& f, Args&&... args)` -Analog of [std::invoke](https://en.cppreference.com/w/cpp/utility/functional/invoke) from C++17 +Analog of [`std::invoke`](https://en.cppreference.com/w/cpp/utility/functional/invoke) from C++17 ### `invoke_hpp::invoke_result` -Analog of [std::invoke_result](https://en.cppreference.com/w/cpp/types/result_of) from C++17 +Analog of [`std::invoke_result`](https://en.cppreference.com/w/cpp/types/result_of) from C++17 + +### `invoke_hpp::invoke_result_t` + +Analog of [`std::invoke_result_t`](https://en.cppreference.com/w/cpp/types/result_of) from C++17 ### `invoke_hpp::is_invocable` -Analog of [std::is_invocable](https://en.cppreference.com/w/cpp/types/is_invocable) from C++17 +Analog of [`std::is_invocable`](https://en.cppreference.com/w/cpp/types/is_invocable) from C++17 + +### `invoke_hpp::is_invocable_r` + +Analog of [`std::is_invocable_r`](https://en.cppreference.com/w/cpp/types/is_invocable) from C++17 ### `invoke_hpp::apply(F&& f, Tuple&& args)` -Analog of [std::apply](https://en.cppreference.com/w/cpp/utility/apply) from C++17 +Analog of [`std::apply`](https://en.cppreference.com/w/cpp/utility/apply) from C++17 ## [License (MIT)](./LICENSE.md) diff --git a/invoke.hpp b/invoke.hpp index e1bbdb4..1224e7b 100644 --- a/invoke.hpp +++ b/invoke.hpp @@ -191,20 +191,26 @@ namespace invoke_hpp { namespace impl { - struct is_invocable_impl_tag {}; + struct is_invocable_r_impl_tag {}; - template < typename Void, typename F, typename... Args > - struct is_invocable_impl + template < typename Void, typename R, typename F, typename... Args > + struct is_invocable_r_impl : std::false_type {}; - template < typename F, typename... Args > - struct is_invocable_impl>, F, Args...> - : std::true_type {}; + template < typename R, typename F, typename... Args > + struct is_invocable_r_impl>, R, F, Args...> + : std::conditional_t< + std::is_void::value, + std::true_type, + std::is_convertible, R>> {}; } + template < typename R, typename F, typename... Args > + struct is_invocable_r + : impl::is_invocable_r_impl {}; + template < typename F, typename... Args > - struct is_invocable - : impl::is_invocable_impl {}; + using is_invocable = is_invocable_r; } // diff --git a/tests.cpp b/tests.cpp index 8954086..72d4e13 100644 --- a/tests.cpp +++ b/tests.cpp @@ -298,6 +298,166 @@ TEST_CASE("is_invocable"){ } } +TEST_CASE("is_invocable_r"){ + SECTION("is_invocable_r_functions"){ + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + } + SECTION("is_not_invocable_r_functions"){ + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + } + SECTION("is_invocable_r_members"){ + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r, int>::value, + "unit test fail"); + static_assert( + inv::is_invocable_r, int>::value, + "unit test fail"); + } + SECTION("is_not_invocable_r_members"){ + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r>::value, + "unit test fail"); + + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r>::value, + "unit test fail"); + + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r, obj2_t>::value, + "unit test fail"); + } + SECTION("is_invocable_r_objects"){ + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + } + SECTION("is_not_invocable_r_objects"){ + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r, obj2_t>::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r, obj2_t>::value, + "unit test fail"); + + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r>::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r>::value, + "unit test fail"); + } +} + TEST_CASE("apply"){ SECTION("apply_functions"){ inv::apply(simple_static_function, std::make_tuple());