diff --git a/.gitignore b/.gitignore index 2300a2d..eb695eb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ build/* +.vscode/* CMakeLists.txt.user diff --git a/README.md b/README.md index 307a258..ae1d996 100644 --- a/README.md +++ b/README.md @@ -34,14 +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 + +### `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 d365795..1224e7b 100644 --- a/invoke.hpp +++ b/invoke.hpp @@ -183,6 +183,36 @@ namespace invoke_hpp using invoke_result_t = typename invoke_result::type; } +// +// is_invocable +// + +namespace invoke_hpp +{ + namespace impl + { + struct is_invocable_r_impl_tag {}; + + template < typename Void, typename R, typename F, typename... Args > + struct is_invocable_r_impl + : std::false_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 > + using is_invocable = is_invocable_r; +} + // // apply // diff --git a/tests.cpp b/tests.cpp index b712ec2..72d4e13 100644 --- a/tests.cpp +++ b/tests.cpp @@ -41,6 +41,9 @@ namespace return v; } }; + + class obj2_t { + }; } TEST_CASE("invoke"){ @@ -100,6 +103,16 @@ TEST_CASE("invoke_result"){ int, inv::invoke_result_t>::value, "unit test fail"); + static_assert( + std::is_same< + int, + inv::invoke_result_t>::value, + "unit test fail"); + static_assert( + std::is_same< + const int&, + inv::invoke_result_t>::value, + "unit test fail"); } SECTION("invoke_result_members"){ static_assert( @@ -140,6 +153,308 @@ TEST_CASE("invoke_result"){ std::is_same, int>>::value, "unit test fail"); + + static_assert( + std::is_same>::value, + "unit test fail"); + static_assert( + std::is_same>::value, + "unit test fail"); + static_assert( + std::is_same, const int&>>::value, + "unit test fail"); + } +} + +TEST_CASE("is_invocable"){ + SECTION("is_invocable_functions"){ + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + } + SECTION("is_not_invocable_functions"){ + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + } + SECTION("is_invocable_members"){ + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable>::value, + "unit test fail"); + + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable>::value, + "unit test fail"); + + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable, int>::value, + "unit test fail"); + } + SECTION("is_not_invocable_members"){ + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable*>::value, + "unit test fail"); + + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable>::value, + "unit test fail"); + + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable, int>::value, + "unit test fail"); + } + SECTION("is_invocable_objects"){ + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable>::value, + "unit test fail"); + + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable>::value, + "unit test fail"); + } + SECTION("is_not_invocable_objects"){ + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable>::value, + "unit test fail"); + } +} + +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"); } }