Skip to content

Commit

Permalink
Make inplace_function SFINAE aware
Browse files Browse the repository at this point in the history
  • Loading branch information
Voultapher committed Apr 2, 2019
1 parent 94debf7 commit 25a4746
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 5 deletions.
39 changes: 34 additions & 5 deletions SG14/inplace_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,39 @@ struct is_valid_inplace_dst : std::true_type
);
};

// C++11 MSVC compatible implementation of std::is_invocable_r.

template<class R> void accept(R);

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

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

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

template<class R, class F, class... Args> struct is_invocable_r_impl<
decltype(accept<R>(std::declval<F>()(std::declval<Args>()...))),
R,
F,
Args...
> : std::true_type {};

template<class R, class F, class... Args> using is_invocable_r = is_invocable_r_impl<
void,
R,
F,
Args...
>;
} // namespace inplace_function_detail

template<
Expand Down Expand Up @@ -187,15 +220,11 @@ 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)
&& 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,
"inplace_function cannot be constructed from non-callable type"
);
#endif
static_assert(std::is_copy_constructible<C>::value,
"inplace_function cannot be constructed from non-copyable type"
);
Expand Down
72 changes: 72 additions & 0 deletions SG14_test/inplace_function_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,77 @@ static void RvalueRefParameter()
g(std::make_unique<int>(42));
}

struct NoDefaultCtor
{
int val;
explicit NoDefaultCtor(int v) : val{v} {}
};

int overloaded_function(stdext::inplace_function<int()>&& exec)
{
return exec();
}

int overloaded_function(stdext::inplace_function<int(int)>&& exec)
{
return exec(int{42});
}

using C_Int1 = int();
using C_Int2 = int(int);
using C_Void = void(int&);

using stdext::inplace_function_detail::is_invocable_r;

static_assert(is_invocable_r<int, C_Int1>::value, "IV A");
static_assert(! is_invocable_r<int, C_Int2>::value, "IV B");
static_assert(! is_invocable_r<int, C_Void>::value, "IV C");

static_assert(is_invocable_r<int, C_Int2, int>::value, "IV D");
static_assert(! is_invocable_r<int, C_Int1, int>::value, "IV E");
static_assert(! is_invocable_r<int, C_Void, int>::value, "IV F");

static_assert(is_invocable_r<void, C_Void, int&>::value, "IV G");
static_assert(! is_invocable_r<void, C_Int1, int&>::value, "IV H");

// cppreference:
// > Determines whether Fn can be invoked with the arguments ArgTypes...
// > to yield a result that is convertible to R.
//
// void is treated specially because a functions return value can be ignored.
// So essentially std::is_convertible<int, void>.
static_assert(is_invocable_r<void, C_Int2, int&>::value, "IV I");
static_assert(is_invocable_r<const void, C_Int2, int&>::value, "IV J");

void test_overloading()
{
EXPECT_EQ(overloaded_function([]() -> int { return 3; }), 3);
EXPECT_EQ(overloaded_function([](int arg) -> int { return arg; }), 42);

using std::is_convertible;
using stdext::inplace_function;

const auto a = []() -> int { return 3; };
static_assert(is_convertible<decltype(a), inplace_function<int()>>::value);
static_assert(!is_convertible<decltype(a), inplace_function<int(int)>>::value);
static_assert(!is_convertible<decltype(a), inplace_function<void(int&)>>::value);

const auto b = [](int&) -> void {};
static_assert(is_convertible<decltype(b), inplace_function<void(int&)>>::value);
static_assert(!is_convertible<decltype(b), inplace_function<int()>>::value);
static_assert(!is_convertible<decltype(b), inplace_function<int(int)>>::value);

const auto c = [](int, NoDefaultCtor) -> int { return 3; };
static_assert(is_convertible<decltype(c), inplace_function<void(int, NoDefaultCtor)>>::value);
static_assert(!is_convertible<decltype(c), inplace_function<int()>>::value);
static_assert(!is_convertible<decltype(c), inplace_function<int(int)>>::value);

const auto d = []() -> void {};
static_assert(is_convertible<decltype(d), inplace_function<void()>>::value);
static_assert(!is_convertible<decltype(d), inplace_function<int()>>::value);
static_assert(!is_convertible<decltype(d), inplace_function<int(int)>>::value);
}

void sg14_test::inplace_function_test()
{
// first set of tests (from Optiver)
Expand Down Expand Up @@ -512,6 +583,7 @@ void sg14_test::inplace_function_test()
test_nullptr();
test_overloaded_operator_new();
test_move_construction_is_noexcept();
test_overloading();
}

#ifdef TEST_MAIN
Expand Down

0 comments on commit 25a4746

Please sign in to comment.