Commit 7dcc645c by Jonathan Wakely Committed by Jonathan Wakely

P0604R0 add invoke_result, is_invocable etc. for C++17

	* include/bits/invoke.h (__invoke): Use __invoke_result instead of
	result_of, and __is_nothrow_invocable instead of
	__is_nothrow_callable.
	* include/bits/shared_ptr_base.h (__shared_ptr): Use __is_invocable
	instead of __is_callable.
	* include/std/functional (invoke): use invoke_result_t instead of
	result_of_t and is_nothrow_invocable instead of is_nothrow_callable.
	(_Not_fn): Use __invoke_result instead of result_of.
	* include/std/type_traits (__result_of_memobj, __result_of_memfun):
	Remove partial specializations for reference_wrapper types.
	(__result_of_impl): Use __inv_unwrap to strip reference_wrapper.
	(__invoke_result): Define replacement for result_of and then use it to
	define result_of.
	(__is_callable_impl, __is_callable, __is_nothrow_callable): Replace
	with __is_invocable_impl, __is_invocable, and __is_nothrow_invocable
	respectively.
	(invoke_result, invoke_result_t): Define for C++17.
	(is_callable, is_nothrow_callable): Replace with is_invocable,
	is_invocable_r, is_nothrow_invocable, and is_nothrow_invocable_r.
	(is_callable_v, is_nothrow_callable_v): Replace with is_invocable_v,
	is_invocable_r_v, is_nothrow_invocable_v, and is_nothrow_invocable_r_v.
	* include/std/variant (hash<variant<T...>>): Use is_nothrow_invocable_v
	instead of is_nothrow_callable_v.
	* testsuite/20_util/function_objects/invoke/59768.cc: Remove unused
	main function.
	* testsuite/20_util/function_objects/not_fn/1.cc: Use is_invocable
	instead of is_callable.
	* testsuite/20_util/is_callable/*: Rename directory and adjust tests
	to use new traits.
	* testsuite/20_util/is_notjrow_callable/*: Likewise.
	* testsuite/20_util/optional/hash.cc: Use is_invocable_v instead of
	is_callable.
	* testsuite/20_util/variant/hash.cc: Likewise.

From-SVN: r246036
parent a147ef11
2017-03-10 Jonathan Wakely <jwakely@redhat.com>
* include/bits/invoke.h (__invoke): Use __invoke_result instead of
result_of, and __is_nothrow_invocable instead of
__is_nothrow_callable.
* include/bits/shared_ptr_base.h (__shared_ptr): Use __is_invocable
instead of __is_callable.
* include/std/functional (invoke): use invoke_result_t instead of
result_of_t and is_nothrow_invocable instead of is_nothrow_callable.
(_Not_fn): Use __invoke_result instead of result_of.
* include/std/type_traits (__result_of_memobj, __result_of_memfun):
Remove partial specializations for reference_wrapper types.
(__result_of_impl): Use __inv_unwrap to strip reference_wrapper.
(__invoke_result): Define replacement for result_of and then use it to
define result_of.
(__is_callable_impl, __is_callable, __is_nothrow_callable): Replace
with __is_invocable_impl, __is_invocable, and __is_nothrow_invocable
respectively.
(invoke_result, invoke_result_t): Define for C++17.
(is_callable, is_nothrow_callable): Replace with is_invocable,
is_invocable_r, is_nothrow_invocable, and is_nothrow_invocable_r.
(is_callable_v, is_nothrow_callable_v): Replace with is_invocable_v,
is_invocable_r_v, is_nothrow_invocable_v, and is_nothrow_invocable_r_v.
* include/std/variant (hash<variant<T...>>): Use is_nothrow_invocable_v
instead of is_nothrow_callable_v.
* testsuite/20_util/function_objects/invoke/59768.cc: Remove unused
main function.
* testsuite/20_util/function_objects/not_fn/1.cc: Use is_invocable
instead of is_callable.
* testsuite/20_util/is_callable/*: Rename directory and adjust tests
to use new traits.
* testsuite/20_util/is_notjrow_callable/*: Likewise.
* testsuite/20_util/optional/hash.cc: Use is_invocable_v instead of
is_callable.
* testsuite/20_util/variant/hash.cc: Likewise.
2017-03-10 George Lander <george.lander@arm.com> 2017-03-10 George Lander <george.lander@arm.com>
* acinclude.m4 (glibcxx_cv_obsolete_isnan): Define * acinclude.m4 (glibcxx_cv_obsolete_isnan): Define
......
...@@ -85,13 +85,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -85,13 +85,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Invoke a callable object. /// Invoke a callable object.
template<typename _Callable, typename... _Args> template<typename _Callable, typename... _Args>
constexpr typename result_of<_Callable&&(_Args&&...)>::type constexpr typename __invoke_result<_Callable, _Args...>::type
__invoke(_Callable&& __fn, _Args&&... __args) __invoke(_Callable&& __fn, _Args&&... __args)
noexcept(__is_nothrow_callable<_Callable&&(_Args&&...)>::value) noexcept(__is_nothrow_invocable<_Callable, _Args...>::value)
{ {
using __result_of = result_of<_Callable&&(_Args&&...)>; using __result = __invoke_result<_Callable, _Args...>;
using __type = typename __result_of::type; using __type = typename __result::type;
using __tag = typename __result_of::__invoke_type; using __tag = typename __result::__invoke_type;
return std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn), return std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn),
std::forward<_Args>(__args)...); std::forward<_Args>(__args)...);
} }
......
...@@ -1085,7 +1085,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1085,7 +1085,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__shared_ptr(_Yp* __p, _Deleter __d) __shared_ptr(_Yp* __p, _Deleter __d)
: _M_ptr(__p), _M_refcount(__p, __d) : _M_ptr(__p), _M_refcount(__p, __d)
{ {
static_assert(__is_callable<_Deleter&(_Yp*&)>::value, static_assert(__is_invocable<_Deleter&, _Yp*&>::value,
"deleter expression d(p) is well-formed"); "deleter expression d(p) is well-formed");
_M_enable_shared_from_this_with(__p); _M_enable_shared_from_this_with(__p);
} }
...@@ -1095,7 +1095,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1095,7 +1095,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a) __shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a)
: _M_ptr(__p), _M_refcount(__p, __d, std::move(__a)) : _M_ptr(__p), _M_refcount(__p, __d, std::move(__a))
{ {
static_assert(__is_callable<_Deleter&(_Yp*&)>::value, static_assert(__is_invocable<_Deleter&, _Yp*&>::value,
"deleter expression d(p) is well-formed"); "deleter expression d(p) is well-formed");
_M_enable_shared_from_this_with(__p); _M_enable_shared_from_this_with(__p);
} }
......
...@@ -73,9 +73,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -73,9 +73,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Invoke a callable object. /// Invoke a callable object.
template<typename _Callable, typename... _Args> template<typename _Callable, typename... _Args>
inline result_of_t<_Callable&&(_Args&&...)> inline invoke_result_t<_Callable, _Args...>
invoke(_Callable&& __fn, _Args&&... __args) invoke(_Callable&& __fn, _Args&&... __args)
noexcept(is_nothrow_callable_v<_Callable&&(_Args&&...)>) noexcept(is_nothrow_invocable_v<_Callable, _Args...>)
{ {
return std::__invoke(std::forward<_Callable>(__fn), return std::__invoke(std::forward<_Callable>(__fn),
std::forward<_Args>(__args)...); std::forward<_Args>(__args)...);
...@@ -903,7 +903,7 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type) ...@@ -903,7 +903,7 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
class _Not_fn class _Not_fn
{ {
template<typename _Fn2, typename... _Args> template<typename _Fn2, typename... _Args>
using __inv_res_t = result_of_t<_Fn2(_Args&&...)>; using __inv_res_t = typename __invoke_result<_Fn2, _Args...>::type;
template<typename _Tp> template<typename _Tp>
static decltype(!std::declval<_Tp>()) static decltype(!std::declval<_Tp>())
......
...@@ -1236,7 +1236,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1236,7 +1236,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ {
size_t size_t
operator()(const variant<_Types...>& __t) const operator()(const variant<_Types...>& __t) const
noexcept((is_nothrow_callable_v<hash<decay_t<_Types>>(_Types)> && ...)) noexcept((is_nothrow_invocable_v<hash<decay_t<_Types>>, _Types> && ...))
{ {
if (!__t.valueless_by_exception()) if (!__t.valueless_by_exception())
{ {
......
...@@ -35,9 +35,3 @@ test01() ...@@ -35,9 +35,3 @@ test01()
std::invoke(&A::foo, refc, 100); // const lvalue std::invoke(&A::foo, refc, 100); // const lvalue
std::invoke(&A::foo, std::move(refc), 100); // const rvalue std::invoke(&A::foo, std::move(refc), 100); // const rvalue
} }
int
main()
{
test01();
}
...@@ -103,7 +103,7 @@ test06() ...@@ -103,7 +103,7 @@ test06()
F f; F f;
auto notf = std::not_fn(f); auto notf = std::not_fn(f);
using NotF = decltype(notf); using NotF = decltype(notf);
static_assert( std::is_callable<NotF()>::value, "cannot negate" ); static_assert( std::is_invocable<NotF>::value, "cannot negate" );
static_assert( !noexcept(notf()), "conversion to bool affects noexcept" ); static_assert( !noexcept(notf()), "conversion to bool affects noexcept" );
} }
...@@ -117,7 +117,7 @@ test07() ...@@ -117,7 +117,7 @@ test07()
F f; F f;
auto notf = std::not_fn(f); auto notf = std::not_fn(f);
using NotF = decltype(notf); using NotF = decltype(notf);
static_assert( !std::is_callable<NotF()>::value, "cannot negate" ); static_assert( !std::is_invocable<NotF>::value, "cannot negate" );
} }
int int
......
// Copyright (C) 2016-2017 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++17" }
// { dg-do compile }
#include <type_traits>
#ifndef IS_CALLABLE_DEFINED
template<typename T, typename R = void>
constexpr bool is_callable()
{
static_assert(std::is_callable<T, R>::value == std::is_callable_v<T, R>);
return std::is_callable_v<T, R>;
}
#endif
void test01()
{
using func_type_v0 = void(*)();
static_assert( is_callable< func_type_v0() >(), "");
static_assert( is_callable< func_type_v0(), void >(), "");
static_assert( ! is_callable< func_type_v0(), void* >(), "");
static_assert( ! is_callable< func_type_v0(), int >(), "");
static_assert( ! is_callable< func_type_v0(int) >(), "");
static_assert( ! is_callable< func_type_v0(int), void >(), "");
static_assert( ! is_callable< func_type_v0(int), void* >(), "");
static_assert( ! is_callable< func_type_v0(int), int >(), "");
using func_type_i0 = int(*)();
static_assert( is_callable< func_type_i0() >(), "");
static_assert( is_callable< func_type_i0(), void >(), "");
static_assert( is_callable< func_type_i0(), int >(), "");
static_assert( ! is_callable< func_type_i0(), int& >(), "");
static_assert( is_callable< func_type_i0(), long >(), "");
static_assert( ! is_callable< func_type_i0(int) >(), "");
static_assert( ! is_callable< func_type_i0(int), void >(), "");
static_assert( ! is_callable< func_type_i0(int), int >(), "");
static_assert( ! is_callable< func_type_i0(int), int& >(), "");
static_assert( ! is_callable< func_type_i0(int), long >(), "");
using func_type_l0 = int&(*)();
static_assert( is_callable< func_type_l0() >(), "");
static_assert( is_callable< func_type_l0(), void >(), "");
static_assert( is_callable< func_type_l0(), int >(), "");
static_assert( is_callable< func_type_l0(), int& >(), "");
static_assert( ! is_callable< func_type_l0(), int&& >(), "");
static_assert( is_callable< func_type_l0(), long >(), "");
static_assert( ! is_callable< func_type_l0(), long& >(), "");
static_assert( ! is_callable< func_type_l0(int) >(), "");
static_assert( ! is_callable< func_type_l0(int), void >(), "");
static_assert( ! is_callable< func_type_l0(int), int >(), "");
static_assert( ! is_callable< func_type_l0(int), int& >(), "");
static_assert( ! is_callable< func_type_l0(int), long >(), "");
using func_type_ii = int(*)(int);
static_assert( ! is_callable< func_type_ii() >(), "");
static_assert( ! is_callable< func_type_ii(), int >(), "");
static_assert( ! is_callable< func_type_ii(), int& >(), "");
static_assert( ! is_callable< func_type_ii(), long >(), "");
static_assert( is_callable< func_type_ii(int) >(), "");
static_assert( is_callable< func_type_ii(int), int >(), "");
static_assert( ! is_callable< func_type_ii(int), int& >(), "");
static_assert( is_callable< func_type_ii(int), long >(), "");
using func_type_il = int(*)(int&);
static_assert( ! is_callable< func_type_il() >(), "");
static_assert( ! is_callable< func_type_il(int) >(), "");
static_assert( ! is_callable< func_type_il(int), int >(), "");
static_assert( ! is_callable< func_type_il(int), int& >(), "");
static_assert( ! is_callable< func_type_il(int), long >(), "");
static_assert( is_callable< func_type_il(int&) >(), "");
static_assert( is_callable< func_type_il(int&), int >(), "");
static_assert( ! is_callable< func_type_il(int&), int& >(), "");
static_assert( is_callable< func_type_il(int&), long >(), "");
using func_type_ir = int(*)(int&&);
static_assert( ! is_callable< func_type_ir() >(), "");
static_assert( is_callable< func_type_ir(int) >(), "");
static_assert( is_callable< func_type_ir(int), int >(), "");
static_assert( ! is_callable< func_type_ir(int), int& >(), "");
static_assert( is_callable< func_type_ir(int), long >(), "");
static_assert( ! is_callable< func_type_ir(int&) >(), "");
static_assert( ! is_callable< func_type_ir(int&), int >(), "");
static_assert( ! is_callable< func_type_ir(int&), int& >(), "");
static_assert( ! is_callable< func_type_ir(int&), long >(), "");
struct X { };
using mem_type_i = int X::*;
static_assert( ! is_callable< mem_type_i() >(), "");
static_assert( ! is_callable< mem_type_i(int) >(), "");
static_assert( ! is_callable< mem_type_i(int), int >(), "");
static_assert( ! is_callable< mem_type_i(int), int& >(), "");
static_assert( ! is_callable< mem_type_i(int), long >(), "");
static_assert( ! is_callable< mem_type_i(int&) >(), "");
static_assert( ! is_callable< mem_type_i(int&), int >(), "");
static_assert( ! is_callable< mem_type_i(int&), int& >(), "");
static_assert( ! is_callable< mem_type_i(int&), long >(), "");
static_assert( is_callable< mem_type_i(X&) >(), "");
static_assert( is_callable< mem_type_i(X&), int >(), "");
static_assert( is_callable< mem_type_i(X&), int& >(), "");
static_assert( is_callable< mem_type_i(X&), long >(), "");
using memfun_type_i = int (X::*)();
static_assert( ! is_callable< memfun_type_i() >(), "");
static_assert( ! is_callable< memfun_type_i(int) >(), "");
static_assert( ! is_callable< memfun_type_i(int&) >(), "");
static_assert( is_callable< memfun_type_i(X&) >(), "");
static_assert( is_callable< memfun_type_i(X&), int >(), "");
static_assert( ! is_callable< memfun_type_i(X&), int& >(), "");
static_assert( is_callable< memfun_type_i(X&), long >(), "");
static_assert( is_callable< memfun_type_i(X*) >(), "");
static_assert( ! is_callable< memfun_type_i(const X&) >(), "");
static_assert( ! is_callable< memfun_type_i(const X&), int >(), "");
static_assert( ! is_callable< memfun_type_i(X&, int) >(), "");
using memfun_type_iic = int& (X::*)(int&) const;
static_assert( ! is_callable< memfun_type_iic() >(), "");
static_assert( ! is_callable< memfun_type_iic(int) >(), "");
static_assert( ! is_callable< memfun_type_iic(int&) >(), "");
static_assert( ! is_callable< memfun_type_iic(X&, int) >(), "");
static_assert( ! is_callable< memfun_type_iic(const X&, int) >(), "");
static_assert( ! is_callable< memfun_type_iic(const X&, int&, int) >(), "");
static_assert( is_callable< memfun_type_iic(const X&, int&) >(), "");
static_assert( is_callable< memfun_type_iic(const X&, int&), int >(), "");
static_assert( is_callable< memfun_type_iic(const X&, int&), int& >(), "");
static_assert( is_callable< memfun_type_iic(const X&, int&), long >(), "");
static_assert( ! is_callable< memfun_type_iic(const X&, int&), long& >(),"");
static_assert( is_callable< memfun_type_iic(const X*, int&) >(), "");
struct F {
int& operator()();
long& operator()() const;
short& operator()(int) &&;
char& operator()(int) const&;
private:
void operator()(int, int);
};
using CF = const F;
static_assert( is_callable< F(), int& >(), "");
static_assert( is_callable< F&(), int& >(), "");
static_assert( is_callable< CF(), long& >(), "");
static_assert( is_callable< CF&(), long& >(), "");
static_assert( is_callable< F(int), short& >(), "");
static_assert( is_callable< F&(int), char& >(), "");
static_assert( is_callable< CF(int), char& >(), "");
static_assert( is_callable< CF&(int), char& >(), "");
static_assert( ! is_callable< F(int, int) >(), "");
}
...@@ -25,5 +25,6 @@ ...@@ -25,5 +25,6 @@
namespace std namespace std
{ {
struct test_type { }; struct test_type { };
template struct is_callable<test_type(), int>; template struct is_invocable<test_type>;
template struct is_invocable_r<int, test_type>;
} }
...@@ -24,5 +24,5 @@ ...@@ -24,5 +24,5 @@
namespace std namespace std
{ {
struct test_type { }; struct test_type { };
template struct __is_callable<test_type(), int>; template struct __is_invocable<test_type>;
} }
...@@ -25,6 +25,13 @@ ...@@ -25,6 +25,13 @@
void test01() void test01()
{ {
// Check for required typedefs // Check for required typedefs
typedef std::is_callable<int(), void> test_type; typedef std::is_invocable<int> test_type;
static_assert( std::is_base_of_v<std::false_type, test_type> );
}
void test02()
{
// Check for required typedefs
typedef std::is_invocable_r<void, int> test_type;
static_assert( std::is_base_of_v<std::false_type, test_type> ); static_assert( std::is_base_of_v<std::false_type, test_type> );
} }
...@@ -24,6 +24,6 @@ ...@@ -24,6 +24,6 @@
void test01() void test01()
{ {
// Check for required typedefs // Check for required typedefs
typedef std::__is_callable<int(), void> test_type; typedef std::__is_invocable<int> test_type;
static_assert( std::is_base_of<std::false_type, test_type>::value, "" ); static_assert( std::is_base_of<std::false_type, test_type>::value, "" );
} }
// Copyright (C) 2016-2017 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++17" }
// { dg-do compile }
#include <type_traits>
#ifndef IS_INVOCABLE_DEFINED
template<typename... T>
constexpr bool is_invocable()
{
constexpr bool result = std::is_invocable_v<T...>;
static_assert(std::is_invocable<T...>::value == result);
return result;
}
template<typename R, typename... T>
constexpr bool is_invocable_r()
{
constexpr bool result = std::is_invocable_r_v<R, T...>;
static_assert(std::is_invocable_r<R, T...>::value == result);
return result;
}
#endif
void test01()
{
using func_type_v0 = void(*)();
static_assert( is_invocable< func_type_v0 >(), "");
static_assert( is_invocable_r<void, func_type_v0 >(), "");
static_assert( ! is_invocable_r<void*, func_type_v0 >(), "");
static_assert( ! is_invocable_r<int, func_type_v0 >(), "");
static_assert( ! is_invocable< func_type_v0, int >(), "");
static_assert( ! is_invocable_r< void, func_type_v0, int >(), "");
static_assert( ! is_invocable_r< void*, func_type_v0, int >(), "");
static_assert( ! is_invocable_r< int, func_type_v0, int >(), "");
using func_type_i0 = int(*)();
static_assert( is_invocable< func_type_i0 >(), "");
static_assert( is_invocable_r<void, func_type_i0 >(), "");
static_assert( is_invocable_r<int, func_type_i0 >(), "");
static_assert( ! is_invocable_r<int&, func_type_i0 >(), "");
static_assert( is_invocable_r<long, func_type_i0 >(), "");
static_assert( ! is_invocable< func_type_i0, int >(), "");
static_assert( ! is_invocable_r< void, func_type_i0, int >(), "");
static_assert( ! is_invocable_r< int, func_type_i0, int >(), "");
static_assert( ! is_invocable_r< int&, func_type_i0, int >(), "");
static_assert( ! is_invocable_r< long, func_type_i0, int >(), "");
using func_type_l0 = int&(*)();
static_assert( is_invocable< func_type_l0 >(), "");
static_assert( is_invocable_r< void, func_type_l0 >(), "");
static_assert( is_invocable_r< int, func_type_l0 >(), "");
static_assert( is_invocable_r< int&, func_type_l0 >(), "");
static_assert( ! is_invocable_r< int&&, func_type_l0 >(), "");
static_assert( is_invocable_r< long, func_type_l0 >(), "");
static_assert( ! is_invocable_r< long&, func_type_l0 >(), "");
static_assert( ! is_invocable< func_type_l0(int) >(), "");
static_assert( ! is_invocable_r< void, func_type_l0, int >(), "");
static_assert( ! is_invocable_r< int, func_type_l0, int >(), "");
static_assert( ! is_invocable_r< int&, func_type_l0, int >(), "");
static_assert( ! is_invocable_r< long, func_type_l0, int >(), "");
using func_type_ii = int(*)(int);
static_assert( ! is_invocable< func_type_ii >(), "");
static_assert( ! is_invocable_r< int, func_type_ii >(), "");
static_assert( ! is_invocable_r< int&, func_type_ii >(), "");
static_assert( ! is_invocable_r< long, func_type_ii >(), "");
static_assert( is_invocable< func_type_ii, int >(), "");
static_assert( is_invocable_r< int, func_type_ii, int >(), "");
static_assert( ! is_invocable_r< int&, func_type_ii, int >(), "");
static_assert( is_invocable_r< long, func_type_ii, int >(), "");
using func_type_il = int(*)(int&);
static_assert( ! is_invocable< func_type_il >(), "");
static_assert( ! is_invocable< func_type_il, int >(), "");
static_assert( ! is_invocable_r< int, func_type_il, int >(), "");
static_assert( ! is_invocable_r< int&, func_type_il, int >(), "");
static_assert( ! is_invocable_r< long, func_type_il, int >(), "");
static_assert( is_invocable< func_type_il, int& >(), "");
static_assert( is_invocable_r< int, func_type_il, int& >(), "");
static_assert( ! is_invocable_r< int&, func_type_il, int& >(), "");
static_assert( is_invocable_r< long, func_type_il, int& >(), "");
using func_type_ir = int(*)(int&&);
static_assert( ! is_invocable< func_type_ir >(), "");
static_assert( is_invocable< func_type_ir, int >(), "");
static_assert( is_invocable_r< int, func_type_ir, int >(), "");
static_assert( ! is_invocable_r< int&, func_type_ir, int >(), "");
static_assert( is_invocable_r< long, func_type_ir, int >(), "");
static_assert( ! is_invocable< func_type_ir, int& >(), "");
static_assert( ! is_invocable_r< int, func_type_ir, int& >(), "");
static_assert( ! is_invocable_r< int&, func_type_ir, int& >(), "");
static_assert( ! is_invocable_r< long, func_type_ir, int& >(), "");
struct X { };
using mem_type_i = int X::*;
static_assert( ! is_invocable< mem_type_i >(), "");
static_assert( ! is_invocable< mem_type_i, int >(), "");
static_assert( ! is_invocable_r< int, mem_type_i, int >(), "");
static_assert( ! is_invocable_r< int&, mem_type_i, int >(), "");
static_assert( ! is_invocable_r< long, mem_type_i, int >(), "");
static_assert( ! is_invocable< mem_type_i, int& >(), "");
static_assert( ! is_invocable_r< int, mem_type_i, int& >(), "");
static_assert( ! is_invocable_r< int&, mem_type_i, int& >(), "");
static_assert( ! is_invocable_r< long, mem_type_i, int& >(), "");
static_assert( is_invocable< mem_type_i, X& >(), "");
static_assert( is_invocable_r< int, mem_type_i, X& >(), "");
static_assert( is_invocable_r< int&, mem_type_i, X& >(), "");
static_assert( is_invocable_r< long, mem_type_i, X& >(), "");
using memfun_type_i = int (X::*)();
static_assert( ! is_invocable< memfun_type_i >(), "");
static_assert( ! is_invocable< memfun_type_i, int >(), "");
static_assert( ! is_invocable< memfun_type_i, int& >(), "");
static_assert( is_invocable< memfun_type_i, X& >(), "");
static_assert( is_invocable_r< int, memfun_type_i, X& >(), "");
static_assert( ! is_invocable_r< int&, memfun_type_i, X& >(), "");
static_assert( is_invocable_r< long, memfun_type_i, X& >(), "");
static_assert( is_invocable< memfun_type_i, X* >(), "");
static_assert( ! is_invocable< memfun_type_i, const X& >(), "");
static_assert( ! is_invocable_r< int, memfun_type_i, const X& >(), "");
static_assert( ! is_invocable< memfun_type_i, X&, int >(), "");
using memfun_type_iic = int& (X::*)(int&) const;
static_assert( ! is_invocable< memfun_type_iic >(), "");
static_assert( ! is_invocable< memfun_type_iic, int >(), "");
static_assert( ! is_invocable< memfun_type_iic, int& >(), "");
static_assert( ! is_invocable< memfun_type_iic, X&, int >(), "");
static_assert( ! is_invocable< memfun_type_iic, const X&, int >(), "");
static_assert( ! is_invocable< memfun_type_iic, const X&, int&, int >(), "");
static_assert( is_invocable< memfun_type_iic, const X&, int& >(), "");
static_assert( is_invocable_r< int, memfun_type_iic, const X&, int& >(), "");
static_assert( is_invocable_r< int&, memfun_type_iic, const X&, int& >(), "");
static_assert( is_invocable_r< long, memfun_type_iic, const X&, int& >(), "");
static_assert( ! is_invocable_r< long&, memfun_type_iic, const X&, int& >(),"");
static_assert( is_invocable< memfun_type_iic, const X*, int& >(), "");
struct F {
int& operator()();
long& operator()() const;
short& operator()(int) &&;
char& operator()(int) const&;
private:
void operator()(int, int);
};
using CF = const F;
static_assert( is_invocable_r< int&, F >(), "");
static_assert( is_invocable_r< int&, F& >(), "");
static_assert( is_invocable_r< long&, CF >(), "");
static_assert( is_invocable_r< long&, CF& >(), "");
static_assert( is_invocable_r< short&, F, int >(), "");
static_assert( is_invocable_r< char&, F&, int >(), "");
static_assert( is_invocable_r< char&, CF, int >(), "");
static_assert( is_invocable_r< char&, CF&, int >(), "");
static_assert( ! is_invocable< F, int, int >(), "");
}
...@@ -19,8 +19,22 @@ ...@@ -19,8 +19,22 @@
#include <type_traits> #include <type_traits>
template<typename T, typename R = void> template<typename... T>
constexpr bool is_callable() { return std::__is_callable<T, R>::value; } constexpr bool is_invocable() { return std::__is_invocable<T...>::value; }
#define IS_CALLABLE_DEFINED template<typename R, typename... T>
constexpr bool is_invocable_conv(std::true_type)
{
using result_type = typename std::__invoke_result<T...>::type;
return std::is_void<R>::value || std::is_convertible<result_type, R>::value;
}
template<typename R, typename... T>
constexpr bool is_invocable_conv(std::false_type) { return false; }
template<typename R, typename... T>
constexpr bool is_invocable_r()
{ return is_invocable_conv<R, T...>(std::__is_invocable<T...>{}); }
#define IS_INVOCABLE_DEFINED
#include "value.cc" #include "value.cc"
...@@ -25,5 +25,6 @@ ...@@ -25,5 +25,6 @@
namespace std namespace std
{ {
struct test_type { }; struct test_type { };
template struct is_nothrow_callable<test_type(), int>; template struct is_nothrow_invocable<test_type>;
template struct is_nothrow_invocable_r<int, test_type>;
} }
...@@ -24,5 +24,5 @@ ...@@ -24,5 +24,5 @@
namespace std namespace std
{ {
struct test_type { }; struct test_type { };
template struct __is_nothrow_callable<test_type(), int>; template struct __is_nothrow_invocable<test_type>;
} }
...@@ -25,6 +25,13 @@ ...@@ -25,6 +25,13 @@
void test01() void test01()
{ {
// Check for required typedefs // Check for required typedefs
typedef std::is_nothrow_callable<int(), void> test_type; typedef std::is_nothrow_invocable<int> test_type;
static_assert( std::is_base_of_v<std::false_type, test_type> );
}
void test02()
{
// Check for required typedefs
typedef std::is_nothrow_invocable_r<void, int> test_type;
static_assert( std::is_base_of_v<std::false_type, test_type> ); static_assert( std::is_base_of_v<std::false_type, test_type> );
} }
...@@ -24,6 +24,6 @@ ...@@ -24,6 +24,6 @@
void test01() void test01()
{ {
// Check for required typedefs // Check for required typedefs
typedef std::__is_nothrow_callable<int(), void> test_type; typedef std::__is_nothrow_invocable<int> test_type;
static_assert( std::is_base_of<std::false_type, test_type>::value, "" ); static_assert( std::is_base_of<std::false_type, test_type>::value, "" );
} }
...@@ -20,55 +20,63 @@ ...@@ -20,55 +20,63 @@
#include <type_traits> #include <type_traits>
#ifndef IS_NT_CALLABLE_DEFINED #ifndef IS_NT_INVOCABLE_DEFINED
template<typename T, typename R = void> template<typename... T>
constexpr bool is_nt_callable() constexpr bool is_nt_invocable()
{ {
static_assert(std::is_nothrow_callable<T, R>::value constexpr bool result = std::is_nothrow_invocable_v<T...>;
== std::is_nothrow_callable_v<T, R>); static_assert(std::is_nothrow_invocable<T...>::value == result);
return std::is_nothrow_callable_v<T, R>; return result;
}
template<typename R, typename... T>
constexpr bool is_nt_invocable_r()
{
constexpr bool result = std::is_nothrow_invocable_r_v<R, T...>;
static_assert(std::is_nothrow_invocable_r<R, T...>::value == result);
return result;
} }
#endif #endif
void test01() void test01()
{ {
using func_type = void(*)(); using func_type = void(*)();
static_assert( ! is_nt_callable< func_type() >(), ""); static_assert( ! is_nt_invocable< func_type>(), "");
#if __cpp_noexcept_function_type #if __cpp_noexcept_function_type
using func_type_nt = void(*)() noexcept; using func_type_nt = void(*)() noexcept;
static_assert( is_nt_callable< func_type_nt() >(), ""); static_assert( is_nt_invocable< func_type_nt >(), "");
#endif #endif
struct X { }; struct X { };
using mem_type = int X::*; using mem_type = int X::*;
static_assert( ! is_nt_callable< mem_type() >(), ""); static_assert( ! is_nt_invocable< mem_type >(), "");
static_assert( ! is_nt_callable< mem_type(int) >(), ""); static_assert( ! is_nt_invocable< mem_type, int >(), "");
static_assert( ! is_nt_callable< mem_type(int&) >(), ""); static_assert( ! is_nt_invocable< mem_type, int& >(), "");
static_assert( is_nt_callable< mem_type(X&) >(), ""); static_assert( is_nt_invocable< mem_type, X& >(), "");
static_assert( is_nt_callable< mem_type(X&), int >(), ""); static_assert( is_nt_invocable_r< int, mem_type, X& >(), "");
static_assert( is_nt_callable< mem_type(X&), int& >(), ""); static_assert( is_nt_invocable_r< int&, mem_type, X& >(), "");
static_assert( is_nt_callable< mem_type(X&), long >(), ""); static_assert( is_nt_invocable_r< long, mem_type, X& >(), "");
static_assert( is_nt_callable< mem_type(X*), int& >(), ""); static_assert( is_nt_invocable_r< int&, mem_type, X* >(), "");
using memfun_type = int (X::*)(); using memfun_type = int (X::*)();
static_assert( ! is_nt_callable< memfun_type() >(), ""); static_assert( ! is_nt_invocable< memfun_type >(), "");
static_assert( ! is_nt_callable< memfun_type(int) >(), ""); static_assert( ! is_nt_invocable< memfun_type, int >(), "");
static_assert( ! is_nt_callable< memfun_type(int&) >(), ""); static_assert( ! is_nt_invocable< memfun_type, int& >(), "");
static_assert( ! is_nt_callable< memfun_type(X&) >(), ""); static_assert( ! is_nt_invocable< memfun_type, X& >(), "");
static_assert( ! is_nt_callable< memfun_type(X*) >(), ""); static_assert( ! is_nt_invocable< memfun_type, X* >(), "");
#if __cpp_noexcept_function_type #if __cpp_noexcept_function_type
using memfun_type_nt = int (X::*)() noexcept; using memfun_type_nt = int (X::*)() noexcept;
static_assert( ! is_nt_callable< memfun_type_nt() >(), ""); static_assert( ! is_nt_invocable< memfun_type_nt >(), "");
static_assert( ! is_nt_callable< memfun_type_nt(int) >(), ""); static_assert( ! is_nt_invocable< memfun_type_nt, int >(), "");
static_assert( ! is_nt_callable< memfun_type_nt(int&) >(), ""); static_assert( ! is_nt_invocable< memfun_type_nt, int& >(), "");
static_assert( is_nt_callable< memfun_type_nt(X&) >(), ""); static_assert( is_nt_invocable< memfun_type_nt, X& >(), "");
static_assert( is_nt_callable< memfun_type_nt(X*) >(), ""); static_assert( is_nt_invocable< memfun_type_nt, X* >(), "");
#endif #endif
struct F { struct F {
...@@ -81,12 +89,12 @@ void test01() ...@@ -81,12 +89,12 @@ void test01()
}; };
using CF = const F; using CF = const F;
static_assert( ! is_nt_callable< F(), int& >(), ""); static_assert( ! is_nt_invocable_r< int&, F >(), "");
static_assert( is_nt_callable< CF(), long& >(), ""); static_assert( is_nt_invocable_r< long&, CF >(), "");
static_assert( ! is_nt_callable< F(int), short& >(), ""); static_assert( ! is_nt_invocable_r< short&, F, int >(), "" );
static_assert( is_nt_callable< F&(int), char& >(), ""); static_assert( is_nt_invocable_r< char&, F&, int >(), "" );
static_assert( is_nt_callable< CF(int), char& >(), ""); static_assert( is_nt_invocable_r< char&, CF, int >(), "" );
static_assert( is_nt_callable< CF&(int), char& >(), ""); static_assert( is_nt_invocable_r< char&, CF&, int >(), "" );
static_assert( ! is_nt_callable< F(int, int) >(), ""); static_assert( ! is_nt_invocable< F, int, int >(), "");
} }
...@@ -19,9 +19,25 @@ ...@@ -19,9 +19,25 @@
#include <type_traits> #include <type_traits>
template<typename T, typename R = void> template<typename... T>
constexpr bool is_nt_callable() constexpr bool is_nt_invocable()
{ return std::__is_nothrow_callable<T, R>::value; } { return std::__is_nothrow_invocable<T...>::value; }
#define IS_NT_CALLABLE_DEFINED template<typename R, typename... T>
constexpr bool is_nt_invocable_conv(std::true_type)
{
using result_type = typename std::__invoke_result<T...>::type;
return std::is_void<R>::value || std::is_convertible<result_type, R>::value;
}
template<typename R, typename... T>
constexpr bool is_nt_invocable_conv(std::false_type) { return false; }
template<typename R, typename... T>
constexpr bool is_nt_invocable_r()
{
return is_nt_invocable_conv<R, T...>(std::__is_nothrow_invocable<T...>{});
}
#define IS_NT_INVOCABLE_DEFINED
#include "value.cc" #include "value.cc"
...@@ -29,12 +29,10 @@ template<class T> ...@@ -29,12 +29,10 @@ template<class T>
auto f(...) -> decltype(std::false_type()); auto f(...) -> decltype(std::false_type());
static_assert(!decltype(f<S>(0))::value, ""); static_assert(!decltype(f<S>(0))::value, "");
static_assert(!std::is_callable< static_assert(!std::is_invocable_v<
std::hash<std::optional<S>>& std::hash<std::optional<S>>&, std::optional<S> const&> );
(std::optional<S> const&)>::value, ""); static_assert(std::is_invocable_v<
static_assert(std::is_callable< std::hash<std::optional<int>>&, std::optional<int> const&> );
std::hash<std::optional<int>>&
(std::optional<int> const&)>::value, "");
int main() int main()
{ {
......
...@@ -33,17 +33,14 @@ static_assert(!decltype(f<std::variant<S>>(0))::value, ""); ...@@ -33,17 +33,14 @@ static_assert(!decltype(f<std::variant<S>>(0))::value, "");
static_assert(!decltype(f<std::variant<S, S>>(0))::value, ""); static_assert(!decltype(f<std::variant<S, S>>(0))::value, "");
static_assert(decltype(f<std::variant<int>>(0))::value, ""); static_assert(decltype(f<std::variant<int>>(0))::value, "");
static_assert(decltype(f<std::variant<int, int>>(0))::value, ""); static_assert(decltype(f<std::variant<int, int>>(0))::value, "");
static_assert(!std::is_callable< static_assert(!std::is_invocable_v<
std::hash<std::variant<S>>&(std::variant<S> const&)>::value, ""); std::hash<std::variant<S>>&, std::variant<S> const&> );
static_assert(!std::is_callable< static_assert(!std::is_invocable_v<
std::hash<std::variant<S, int>>& std::hash<std::variant<S, int>>&, std::variant<S, int> const&> );
(std::variant<S, int> const&)>::value, ""); static_assert(std::is_invocable_v<
static_assert(std::is_callable< std::hash<std::variant<int>>&, std::variant<int> const&> );
std::hash<std::variant<int>>& static_assert(std::is_invocable_v<
(std::variant<int> const&)>::value, ""); std::hash<std::variant<int, int>>&, std::variant<int, int> const&> );
static_assert(std::is_callable<
std::hash<std::variant<int, int>>&
(std::variant<int, int> const&)>::value, "");
int main() int main()
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment