Add 'is_callable' and 'is_nothrow_callable' traits and cleanup INVOKE.

The primary purpose of this patch is to add the 'is_callable' traits.
Since 'is_nothrow_callable' required making 'INVOKE' conditionally noexcept
I also took this oppertunity to implement a constexpr version of INVOKE.
This fixes 'std::experimental::apply' which required constexpr 'INVOKE support'.

This patch will be followed up with some cleanup. Primarly removing most
of "__member_function_traits" since it's no longer used by INVOKE (in C++11 at least).


git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@266836 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Eric Fiselier
2016-04-20 00:14:32 +00:00
parent 9c6f00d616
commit 8d5cbd7ce2
15 changed files with 732 additions and 237 deletions

View File

@@ -0,0 +1,35 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <functional>
// template<CopyConstructible Fn, CopyConstructible... Types>
// unspecified bind(Fn, Types...);
// template<Returnable R, CopyConstructible Fn, CopyConstructible... Types>
// unspecified bind(Fn, Types...);
// https://llvm.org/bugs/show_bug.cgi?id=23141
#include <functional>
#include <type_traits>
struct Fun
{
template<typename T, typename U>
void operator()(T && t, U && u) const
{
static_assert(std::is_same<U, int &>::value, "");
}
};
int main()
{
std::bind(Fun{}, std::placeholders::_1, 42)("hello");
}

View File

@@ -260,8 +260,11 @@ void test_derived_from_ref_wrap() {
DerivedFromRefWrap<int> d(x);
auto get_fn = &std::reference_wrapper<int>::get;
auto& ret = std::__invoke(get_fn, r);
auto& cret = std::__invoke_constexpr(get_fn, r);
assert(&ret == &x);
assert(&cret == &x);
auto& ret2 = std::__invoke(get_fn, d);
auto& cret2 = std::__invoke_constexpr(get_fn, d);
assert(&ret2 == &x);
auto& ret3 = std::__invoke(get_fn, r2);
assert(&ret3 == &x);

View File

@@ -185,11 +185,22 @@ private:
#else
void runTest(Fn M, T& obj, ObjectType* expect ) {
#endif
static_assert((std::is_same<
decltype(std::__invoke(M, std::forward<T>(obj))), Expect
>::value), "");
Expect e = std::__invoke(M, std::forward<T>(obj));
assert(&e == expect);
{
static_assert((std::is_same<
decltype(std::__invoke(M, std::forward<T>(obj))), Expect
>::value), "");
Expect e = std::__invoke(M, std::forward<T>(obj));
assert(&e == expect);
}
#if TEST_STD_VER >= 11
{
static_assert((std::is_same<
decltype(std::__invoke_constexpr(M, std::forward<T>(obj))), Expect
>::value), "");
Expect e = std::__invoke_constexpr(M, std::forward<T>(obj));
assert(&e == expect);
}
#endif
}
};

View File

@@ -271,89 +271,185 @@ private:
ArgType a0, a1, a2;
//==========================================================================
// BULLET 1 AND 2 TEST METHODS
// BULLET 1, 2 AND 3 TEST METHODS
//==========================================================================
template <class MethodPtr, class ObjectT>
void runTestImp(Int<0>, MethodPtr ptr, ObjectT& object) {
static_assert((std::is_same<
decltype(std::__invoke(ptr, object_cast(object)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(ptr, object_cast(object));
assert(ID::checkCalled(ret));
{
static_assert((std::is_same<
decltype(std::__invoke(ptr, object_cast(object)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(ptr, object_cast(object));
assert(ID::checkCalled(ret));
}
#if TEST_STD_VER >= 11
{
static_assert((std::is_same<
decltype(std::__invoke_constexpr(ptr, object_cast(object)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke_constexpr(ptr, object_cast(object));
assert(ID::checkCalled(ret));
}
#endif
}
template <class MethodPtr, class ObjectT>
void runTestImp(Int<1>, MethodPtr ptr, ObjectT& object) {
static_assert((std::is_same<
decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0));
assert(ID::checkCalled(ret));
{
static_assert((std::is_same<
decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0));
assert(ID::checkCalled(ret));
}
#if TEST_STD_VER >= 11
{
static_assert((std::is_same<
decltype(std::__invoke_constexpr(ptr, object_cast(object), arg_cast(a0)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke_constexpr(ptr, object_cast(object), arg_cast(a0));
assert(ID::checkCalled(ret));
}
#endif
}
template <class MethodPtr, class ObjectT>
void runTestImp(Int<2>, MethodPtr ptr, ObjectT& object) {
static_assert((std::is_same<
decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1));
assert(ID::checkCalled(ret));
{
static_assert((std::is_same<
decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1));
assert(ID::checkCalled(ret));
}
#if TEST_STD_VER >= 11
{
static_assert((std::is_same<
decltype(std::__invoke_constexpr(ptr, object_cast(object), arg_cast(a0), arg_cast(a1)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke_constexpr(ptr, object_cast(object), arg_cast(a0), arg_cast(a1));
assert(ID::checkCalled(ret));
}
#endif
}
template <class MethodPtr, class ObjectT>
void runTestImp(Int<3>, MethodPtr ptr, ObjectT& object) {
static_assert((std::is_same<
decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
assert(ID::checkCalled(ret));
{
static_assert((std::is_same<
decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
assert(ID::checkCalled(ret));
}
#if TEST_STD_VER >= 11
{
static_assert((std::is_same<
decltype(std::__invoke_constexpr(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke_constexpr(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
assert(ID::checkCalled(ret));
}
#endif
}
//==========================================================================
// BULLET 5 TEST METHODS
// BULLET 7 TEST METHODS
//==========================================================================
template <class ObjectT>
void runTestImp(Int<0>, ObjectT& object) {
static_assert((std::is_same<
decltype(std::__invoke(object_cast(object)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(object_cast(object));
assert(ID::checkCalled(ret));
{
static_assert((std::is_same<
decltype(std::__invoke(object_cast(object)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(object_cast(object));
assert(ID::checkCalled(ret));
}
#if TEST_STD_VER >= 11
{
static_assert((std::is_same<
decltype(std::__invoke_constexpr(object_cast(object)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke_constexpr(object_cast(object));
assert(ID::checkCalled(ret));
}
#endif
}
template <class ObjectT>
void runTestImp(Int<1>, ObjectT& object) {
static_assert((std::is_same<
decltype(std::__invoke(object_cast(object), arg_cast(a0)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(object_cast(object), arg_cast(a0));
assert(ID::checkCalled(ret));
{
static_assert((std::is_same<
decltype(std::__invoke(object_cast(object), arg_cast(a0)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(object_cast(object), arg_cast(a0));
assert(ID::checkCalled(ret));
}
#if TEST_STD_VER >= 11
{
static_assert((std::is_same<
decltype(std::__invoke_constexpr(object_cast(object), arg_cast(a0)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke_constexpr(object_cast(object), arg_cast(a0));
assert(ID::checkCalled(ret));
}
#endif
}
template <class ObjectT>
void runTestImp(Int<2>, ObjectT& object) {
static_assert((std::is_same<
decltype(std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1));
assert(ID::checkCalled(ret));
{
static_assert((std::is_same<
decltype(std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1));
assert(ID::checkCalled(ret));
}
#if TEST_STD_VER >= 11
{
static_assert((std::is_same<
decltype(std::__invoke_constexpr(object_cast(object), arg_cast(a0), arg_cast(a1)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke_constexpr(object_cast(object), arg_cast(a0), arg_cast(a1));
assert(ID::checkCalled(ret));
}
#endif
}
template <class ObjectT>
void runTestImp(Int<3>, ObjectT& object) {
static_assert((std::is_same<
decltype(std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
assert(ID::checkCalled(ret));
{
static_assert((std::is_same<
decltype(std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
assert(ID::checkCalled(ret));
}
#if TEST_STD_VER >= 11
{
static_assert((std::is_same<
decltype(std::__invoke_constexpr(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke_constexpr(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
assert(ID::checkCalled(ret));
}
#endif
}
};