Skip to content

Commit

Permalink
Solve WG21-SG14#149, except for the part in WG21-SG14#150 (which is a…
Browse files Browse the repository at this point in the history
…n important part).
  • Loading branch information
Quuxplusone committed Feb 4, 2019
1 parent e57d7e5 commit 92649fa
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 2 deletions.
43 changes: 41 additions & 2 deletions SG14/inplace_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<class Void, class F, class... Args>
struct is_invocable_helper : std::false_type {};

template<class F, class... Args>
struct is_invocable_helper<decltype(std::declval<F()>()()(std::declval<Args>()...), void()), F, Args...> : std::true_type {};

template<class F, class... Args>
struct is_invocable : is_invocable_helper<void, F, Args...> {};

template<class Void, class R, class F, class... Args>
struct is_invocable_r_helper : std::false_type {};

template<class R, class F, class... Args>
struct is_invocable_r_helper<decltype(std::declval<F()>()()(std::declval<Args>()...), void()), R, F, Args...> : std::is_convertible<decltype(std::declval<F()>()()(std::declval<Args>()...)), R> {};

template<class R, class F, class... Args>
struct is_invocable_r : is_invocable_r_helper<void, R, F, Args...> {};

template<class F, class... Args> struct is_invocable_r<void, F, Args...> : is_invocable<F, Args...> {};
template<class F, class... Args> struct is_invocable_r<const void, F, Args...> : is_invocable<F, Args...> {};
template<class F, class... Args> struct is_invocable_r<volatile void, F, Args...> : is_invocable<F, Args...> {};
template<class F, class... Args> struct is_invocable_r<const volatile void, F, Args...> : is_invocable<F, Args...> {};

static_assert(is_invocable<int(*)(int), int>::value, "sanity check");
static_assert(is_invocable_r<int*, int*(*)(int), int>::value, "sanity check");
static_assert(is_invocable_r<void, int*(*)(int), int>::value, "sanity check");
static_assert(is_invocable_r<void, void(*)(int), int>::value, "sanity check");
static_assert(!is_invocable_r<int, void(*)(int), int>::value, "sanity check");
static_assert(!is_invocable_r<void, void(*)(int)>::value, "sanity check");
static_assert(is_invocable_r<void, void(*)()>::value, "sanity check");
#endif

} // namespace inplace_function_detail

template<
Expand Down Expand Up @@ -187,12 +222,16 @@ class inplace_function<R(Args...), Capacity, Alignment>
typename = std::enable_if_t<
!(std::is_same<C, inplace_function>::value
|| std::is_convertible<C, inplace_function>::value)
>,
typename = std::enable_if_t<
inplace_function_detail::is_invocable_r<R, C&, Args...>::value
>
>
inplace_function(T&& closure)
{
#if __cplusplus >= 201703L
static_assert(std::is_invocable_r<R, C, Args...>::value,
#if __cpp_lib_is_invocable >= 201703L
static_assert(std::is_invocable_r<R, C&, Args...>::value,
// SFINAE should prevent this assertion from ever triggering anymore.
"inplace_function cannot be constructed from non-callable type"
);
#endif
Expand Down
30 changes: 30 additions & 0 deletions SG14_test/inplace_function_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,35 @@ static void test_void_returning_function()
f();
}

template<class FirstSig, class OtherSig>
struct test_sfinae_helper {
static bool accepts(stdext::inplace_function<FirstSig>) {
return true;
}
static bool accepts(stdext::inplace_function<OtherSig>) {
return false;
}
};

void test_sfinae_on_noncallable()
{
if (true) {
test_sfinae_helper<void(), void(size_t)> tester;
assert(tester.accepts([](){ }) == true);
assert(tester.accepts([](size_t){ }) == false);
}
if (true) {
test_sfinae_helper<int*(), int()> tester;
assert(tester.accepts([](){ return nullptr; }) == true);
assert(tester.accepts([](){ return 42; }) == false);
}
if (true) {
test_sfinae_helper<void(), int()> tester;
assert(tester.accepts([](){ return; }) == true);
assert(tester.accepts([](){ return nullptr; }) == true);
}
}

void sg14_test::inplace_function_test()
{
// first set of tests (from Optiver)
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 92649fa

Please sign in to comment.