From 92649fa8a82eb90cca6774b0097ddc10f8c71de1 Mon Sep 17 00:00:00 2001 From: Arthur O'Dwyer Date: Sun, 3 Feb 2019 20:33:47 -0500 Subject: [PATCH] Solve #149, except for the part in #150 (which is an important part). --- SG14/inplace_function.h | 43 +++++++++++++++++++++++++++-- SG14_test/inplace_function_test.cpp | 30 ++++++++++++++++++++ 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/SG14/inplace_function.h b/SG14/inplace_function.h index 1ca1cd01..de3f2f16 100644 --- a/SG14/inplace_function.h +++ b/SG14/inplace_function.h @@ -150,6 +150,41 @@ struct is_valid_inplace_dst : std::true_type ); }; +#if __cpp_lib_is_invocable >= 201703L +using std::is_invocable_r; +#else +template +struct is_invocable_helper : std::false_type {}; + +template +struct is_invocable_helper()()(std::declval()...), void()), F, Args...> : std::true_type {}; + +template +struct is_invocable : is_invocable_helper {}; + +template +struct is_invocable_r_helper : std::false_type {}; + +template +struct is_invocable_r_helper()()(std::declval()...), void()), R, F, Args...> : std::is_convertible()()(std::declval()...)), R> {}; + +template +struct is_invocable_r : is_invocable_r_helper {}; + +template struct is_invocable_r : is_invocable {}; +template struct is_invocable_r : is_invocable {}; +template struct is_invocable_r : is_invocable {}; +template struct is_invocable_r : is_invocable {}; + +static_assert(is_invocable::value, "sanity check"); +static_assert(is_invocable_r::value, "sanity check"); +static_assert(is_invocable_r::value, "sanity check"); +static_assert(is_invocable_r::value, "sanity check"); +static_assert(!is_invocable_r::value, "sanity check"); +static_assert(!is_invocable_r::value, "sanity check"); +static_assert(is_invocable_r::value, "sanity check"); +#endif + } // namespace inplace_function_detail template< @@ -187,12 +222,16 @@ class inplace_function typename = std::enable_if_t< !(std::is_same::value || std::is_convertible::value) + >, + typename = std::enable_if_t< + inplace_function_detail::is_invocable_r::value > > inplace_function(T&& closure) { -#if __cplusplus >= 201703L - static_assert(std::is_invocable_r::value, +#if __cpp_lib_is_invocable >= 201703L + static_assert(std::is_invocable_r::value, + // SFINAE should prevent this assertion from ever triggering anymore. "inplace_function cannot be constructed from non-callable type" ); #endif diff --git a/SG14_test/inplace_function_test.cpp b/SG14_test/inplace_function_test.cpp index f8cc3424..f36acdf9 100644 --- a/SG14_test/inplace_function_test.cpp +++ b/SG14_test/inplace_function_test.cpp @@ -414,6 +414,35 @@ static void test_void_returning_function() f(); } +template +struct test_sfinae_helper { + static bool accepts(stdext::inplace_function) { + return true; + } + static bool accepts(stdext::inplace_function) { + return false; + } +}; + +void test_sfinae_on_noncallable() +{ + if (true) { + test_sfinae_helper tester; + assert(tester.accepts([](){ }) == true); + assert(tester.accepts([](size_t){ }) == false); + } + if (true) { + test_sfinae_helper tester; + assert(tester.accepts([](){ return nullptr; }) == true); + assert(tester.accepts([](){ return 42; }) == false); + } + if (true) { + test_sfinae_helper tester; + assert(tester.accepts([](){ return; }) == true); + assert(tester.accepts([](){ return nullptr; }) == true); + } +} + void sg14_test::inplace_function_test() { // first set of tests (from Optiver) @@ -497,6 +526,7 @@ void sg14_test::inplace_function_test() test_overloaded_operator_new(); test_void_returning_function(); test_move_construction_is_noexcept(); + test_sfinae_on_noncallable(); } #ifdef TEST_MAIN