From: Jonathan Wakely Date: Sun, 25 Oct 2015 00:00:54 +0000 (+0100) Subject: Implement C++17 std::invoke and LWG DR 2219 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=93e954005f7c39b4cae859f6b2923267f22d6146;p=gcc.git Implement C++17 std::invoke and LWG DR 2219 * include/std/functional (__invoke_impl): New overloads. (__invoke): Replace with a single function calling __invoke_impl. (invoke): Add C++17 std::invoke. (reference_wrapper::operator()): Qualify call to __invoke. (_Mem_fn_traits_base, _Mem_fn_traits): Remove unused typedefs. (_Mem_fn_base): Remove unused typedefs and implement call operator in terms of __invoke. * include/std/future (__future_base::_Async_state_commonV2): Do not pass reference_wrapper as object argument to call_once. * include/std/type_traits (result_of): Define nested __invoke_type. Handle reference_wrapper as per LWG 2219. * testsuite/20_util/bind/ref_neg.cc: Adjust dg-error directives. * testsuite/20_util/function_objects/mem_fn/55463.cc: Remove tests using member functions of reference_wrapper. From-SVN: r229290 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 4f0a4bd5395..7c88b8f7161 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,20 @@ +2015-10-24 Jonathan Wakely + + * include/std/functional (__invoke_impl): New overloads. + (__invoke): Replace with a single function calling __invoke_impl. + (invoke): Add C++17 std::invoke. + (reference_wrapper::operator()): Qualify call to __invoke. + (_Mem_fn_traits_base, _Mem_fn_traits): Remove unused typedefs. + (_Mem_fn_base): Remove unused typedefs and implement call operator in + terms of __invoke. + * include/std/future (__future_base::_Async_state_commonV2): Do not + pass reference_wrapper as object argument to call_once. + * include/std/type_traits (result_of): Define nested __invoke_type. + Handle reference_wrapper as per LWG 2219. + * testsuite/20_util/bind/ref_neg.cc: Adjust dg-error directives. + * testsuite/20_util/function_objects/mem_fn/55463.cc: Remove tests + using member functions of reference_wrapper. + 2015-10-24 Jonathan Wakely * include/std/future (async): Use deferred function on exception. diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index 7dd149ada0a..f1dc8393af8 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -184,48 +184,77 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : _Weak_result_type_impl::type> { }; - /** - * Invoke a function object, which may be either a member pointer or a - * function object. The first parameter will tell which. - */ - template - inline - typename enable_if< - (!is_member_pointer<_Functor>::value - && !is_function<_Functor>::value - && !is_function::type>::value), - typename result_of<_Functor&(_Args&&...)>::type - >::type - __invoke(_Functor& __f, _Args&&... __args) + template + inline _Res + __invoke_impl(__invoke_other, _Fn&& __f, _Args&&... __args) + noexcept(noexcept(std::forward<_Fn>(__f)(std::forward<_Args>(__args)...))) + { return std::forward<_Fn>(__f)(std::forward<_Args>(__args)...); } + + template + inline _Res + __invoke_impl(__invoke_memfun_ref, _MemFun&& __f, _Tp&& __t, + _Args&&... __args) + noexcept(noexcept((forward<_Tp>(__t).*__f)(forward<_Args>(__args)...))) + { return (forward<_Tp>(__t).*__f)(forward<_Args>(__args)...); } + + template + inline _Res + __invoke_impl(__invoke_memfun_ref, _MemFun&& __f, + reference_wrapper<_Tp> __t, _Args&&... __args) + noexcept(noexcept((__t.get().*__f)(forward<_Args>(__args)...))) + { return (__t.get().*__f)(forward<_Args>(__args)...); } + + template + inline _Res + __invoke_impl(__invoke_memfun_deref, _MemFun&& __f, _Tp&& __t, + _Args&&... __args) + noexcept(noexcept(((*forward<_Tp>(__t)).*__f)(forward<_Args>(__args)...))) + { return ((*forward<_Tp>(__t)).*__f)(forward<_Args>(__args)...); } + + template + inline _Res + __invoke_impl(__invoke_memobj_ref, _MemFun&& __f, _Tp&& __t) + noexcept(noexcept(forward<_Tp>(__t).*__f)) + { return forward<_Tp>(__t).*__f; } + + template + inline _Res + __invoke_impl(__invoke_memobj_ref, _MemFun&& __f, + reference_wrapper<_Tp> __t) + noexcept(noexcept(__t.get().*__f)) + { return __t.get().*__f; } + + template + inline _Res + __invoke_impl(__invoke_memobj_deref, _MemFun&& __f, _Tp&& __t, + _Args&&... __args) + noexcept(noexcept((*forward<_Tp>(__t)).*__f)) + { return (*forward<_Tp>(__t)).*__f; } + + /// Invoke a callable object. + template + inline typename result_of<_Callable&&(_Args&&...)>::type + __invoke(_Callable&& __fn, _Args&&... __args) { - return __f(std::forward<_Args>(__args)...); + using __result_of = result_of<_Callable&&(_Args&&...)>; + using __type = typename __result_of::type; + using __tag = typename __result_of::__invoke_type; + return std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn), + std::forward<_Args>(__args)...); } - template - inline - typename enable_if< - (is_member_pointer<_Functor>::value - && !is_function<_Functor>::value - && !is_function::type>::value), - typename result_of<_Functor(_Args&&...)>::type - >::type - __invoke(_Functor& __f, _Args&&... __args) - { - return std::mem_fn(__f)(std::forward<_Args>(__args)...); - } +#if __cplusplus > 201402L +# define __cpp_lib_invoke 201411 - // To pick up function references (that will become function pointers) - template - inline - typename enable_if< - (is_pointer<_Functor>::value - && is_function::type>::value), - typename result_of<_Functor(_Args&&...)>::type - >::type - __invoke(_Functor __f, _Args&&... __args) + /// Invoke a callable object. + template + inline result_of_t<_Callable&&(_Args&&...)> + invoke(_Callable&& __fn, _Args&&... __args) { - return __f(std::forward<_Args>(__args)...); + return std::__invoke(std::forward<_Callable>(__fn), + std::forward<_Args>(__args)...); } +#endif /** * Knowing which of unary_function and binary_function _Tp derives @@ -425,7 +454,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typename result_of<_Tp&(_Args&&...)>::type operator()(_Args&&... __args) const { - return __invoke(get(), std::forward<_Args>(__args)...); + return std::__invoke(get(), std::forward<_Args>(__args)...); } }; @@ -504,8 +533,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct _Mem_fn_traits_base { using __result_type = _Res; - using __class_type = _Class; - using __arg_types = _Pack<_ArgTypes...>; using __maybe_type = _Maybe_unary_or_binary_function<_Res, _Class*, _ArgTypes...>; using __arity = integral_constant; @@ -516,18 +543,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) _CV _REF> \ : _Mem_fn_traits_base<_Res, _CV _Class, _ArgTypes...> \ { \ - using __pmf_type = _Res (_Class::*)(_ArgTypes...) _CV _REF; \ - using __lvalue = _LVAL; \ - using __rvalue = _RVAL; \ using __vararg = false_type; \ }; \ template \ struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes... ...) _CV _REF> \ : _Mem_fn_traits_base<_Res, _CV _Class, _ArgTypes...> \ { \ - using __pmf_type = _Res (_Class::*)(_ArgTypes... ...) _CV _REF; \ - using __lvalue = _LVAL; \ - using __rvalue = _RVAL; \ using __vararg = true_type; \ }; @@ -551,173 +572,51 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type) { using _Traits = _Mem_fn_traits<_MemFunPtr>; - using _Class = typename _Traits::__class_type; - using _ArgTypes = typename _Traits::__arg_types; - using _Pmf = typename _Traits::__pmf_type; - using _Arity = typename _Traits::__arity; using _Varargs = typename _Traits::__vararg; template friend struct _Bind_check_arity; - // for varargs functions we just check the number of arguments, - // otherwise we also check they are convertible. - template - using _CheckArgs = typename conditional<_Varargs::value, - __bool_constant<(_Args::value >= _ArgTypes::value)>, - _AllConvertible<_Args, _ArgTypes> - >::type; + _MemFunPtr _M_pmf; public: - using result_type = typename _Traits::__result_type; - - explicit constexpr _Mem_fn_base(_Pmf __pmf) : _M_pmf(__pmf) { } - - // Handle objects - template>>> - result_type - operator()(_Class& __object, _Args&&... __args) const - { return (__object.*_M_pmf)(std::forward<_Args>(__args)...); } - template>>> - result_type - operator()(_Class&& __object, _Args&&... __args) const - { - return (std::move(__object).*_M_pmf)(std::forward<_Args>(__args)...); - } - - // Handle pointers - template>>> - result_type - operator()(_Class* __object, _Args&&... __args) const - { return (__object->*_M_pmf)(std::forward<_Args>(__args)...); } - - // Handle smart pointers, references and pointers to derived - template, _NotSame<_Class*, _Tp>, - _CheckArgs<_Pack<_Args...>>>> - result_type - operator()(_Tp&& __object, _Args&&... __args) const - { - return _M_call(std::forward<_Tp>(__object), &__object, - std::forward<_Args>(__args)...); - } - - // Handle reference wrappers - template, typename _Traits::__lvalue, - _CheckArgs<_Pack<_Args...>>>> - result_type - operator()(reference_wrapper<_Tp> __ref, _Args&&... __args) const - { return operator()(__ref.get(), std::forward<_Args>(__args)...); } - - private: - template - result_type - _M_call(_Tp&& __object, const volatile _Class *, - _Args&&... __args) const - { - return (std::forward<_Tp>(__object).*_M_pmf) - (std::forward<_Args>(__args)...); - } + using result_type = typename _Traits::__result_type; - template - result_type - _M_call(_Tp&& __ptr, const volatile void *, _Args&&... __args) const - { return ((*__ptr).*_M_pmf)(std::forward<_Args>(__args)...); } + explicit constexpr + _Mem_fn_base(_MemFunPtr __pmf) noexcept : _M_pmf(__pmf) { } - _Pmf _M_pmf; + template + auto + operator()(_Args&&... __args) const + noexcept(noexcept(std::__invoke(_M_pmf, forward<_Args>(__args)...))) + -> decltype(std::__invoke(_M_pmf, forward<_Args>(__args)...)) + { return std::__invoke(_M_pmf, std::forward<_Args>(__args)...); } }; // Partial specialization for member object pointers. - template - class _Mem_fn_base<_Res _Class::*, false> + template + class _Mem_fn_base<_MemObjPtr, false> { - using __pm_type = _Res _Class::*; - - // This bit of genius is due to Peter Dimov, improved slightly by - // Douglas Gregor. - // Made less elegant to support perfect forwarding and noexcept. - template - auto - _M_call(_Tp&& __object, const _Class *) const noexcept - -> decltype(std::forward<_Tp>(__object).*std::declval<__pm_type&>()) - { return std::forward<_Tp>(__object).*_M_pm; } - - template - auto - _M_call(_Tp&& __object, _Up * const *) const noexcept - -> decltype((*std::forward<_Tp>(__object)).*std::declval<__pm_type&>()) - { return (*std::forward<_Tp>(__object)).*_M_pm; } - - template - auto - _M_call(_Tp&& __ptr, const volatile void*) const - noexcept(noexcept((*__ptr).*std::declval<__pm_type&>())) - -> decltype((*__ptr).*std::declval<__pm_type&>()) - { return (*__ptr).*_M_pm; } - using _Arity = integral_constant; using _Varargs = false_type; template friend struct _Bind_check_arity; + _MemObjPtr _M_pm; + public: explicit constexpr - _Mem_fn_base(_Res _Class::*__pm) noexcept : _M_pm(__pm) { } - - // Handle objects - _Res& - operator()(_Class& __object) const noexcept - { return __object.*_M_pm; } - - const _Res& - operator()(const _Class& __object) const noexcept - { return __object.*_M_pm; } - - _Res&& - operator()(_Class&& __object) const noexcept - { return std::forward<_Class>(__object).*_M_pm; } - - const _Res&& - operator()(const _Class&& __object) const noexcept - { return std::forward(__object).*_M_pm; } + _Mem_fn_base(_MemObjPtr __pm) noexcept : _M_pm(__pm) { } - // Handle pointers - _Res& - operator()(_Class* __object) const noexcept - { return __object->*_M_pm; } - - const _Res& - operator()(const _Class* __object) const noexcept - { return __object->*_M_pm; } - - // Handle smart pointers and derived - template>> - auto - operator()(_Tp&& __unknown) const - noexcept(noexcept(std::declval<_Mem_fn_base*>()->_M_call - (std::forward<_Tp>(__unknown), &__unknown))) - -> decltype(this->_M_call(std::forward<_Tp>(__unknown), &__unknown)) - { return _M_call(std::forward<_Tp>(__unknown), &__unknown); } - - template>> + template auto - operator()(reference_wrapper<_Tp> __ref) const - noexcept(noexcept(std::declval<_Mem_fn_base&>()(__ref.get()))) - -> decltype((*this)(__ref.get())) - { return (*this)(__ref.get()); } - - private: - _Res _Class::*_M_pm; + operator()(_Tp&& __obj) const + noexcept(noexcept(std::__invoke(_M_pm, forward<_Tp>(__obj)))) + -> decltype(std::__invoke(_M_pm, std::forward<_Tp>(__obj))) + { return std::__invoke(_M_pm, std::forward<_Tp>(__obj)); } }; template diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future index 93889cd49d2..014658f8db8 100644 --- a/libstdc++-v3/include/std/future +++ b/libstdc++-v3/include/std/future @@ -1641,7 +1641,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // the shared state, whichever happens first. virtual void _M_complete_async() { _M_join(); } - void _M_join() { std::call_once(_M_once, &thread::join, ref(_M_thread)); } + void _M_join() { std::call_once(_M_once, &thread::join, &_M_thread); } thread _M_thread; once_flag _M_once; diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index e291047ad8b..e08131b2c6d 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -2219,13 +2219,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #define __cpp_lib_result_of_sfinae 201210 + struct __invoke_memfun_ref { }; + struct __invoke_memfun_deref { }; + struct __invoke_memobj_ref { }; + struct __invoke_memobj_deref { }; + struct __invoke_other { }; + + // Associate a tag type with a specialization of __success_type. + template + struct __result_of_success : __success_type<_Tp> + { using __invoke_type = _Tag; }; + // [func.require] paragraph 1 bullet 1: struct __result_of_memfun_ref_impl { template - static __success_type().*std::declval<_Fp>())(std::declval<_Args>()...) - )> _S_test(int); + ), __invoke_memfun_ref> _S_test(int); template static __failure_type _S_test(...); @@ -2242,9 +2253,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __result_of_memfun_deref_impl { template - static __success_type()).*std::declval<_Fp>())(std::declval<_Args>()...) - )> _S_test(int); + ), __invoke_memfun_deref> _S_test(int); template static __failure_type _S_test(...); @@ -2261,9 +2272,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __result_of_memobj_ref_impl { template - static __success_type().*std::declval<_Fp>() - )> _S_test(int); + ), __invoke_memobj_ref> _S_test(int); template static __failure_type _S_test(...); @@ -2280,9 +2291,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __result_of_memobj_deref_impl { template - static __success_type()).*std::declval<_Fp>() - )> _S_test(int); + ), __invoke_memobj_deref> _S_test(int); template static __failure_type _S_test(...); @@ -2327,6 +2338,49 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >::type::type type; }; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2219. INVOKE-ing a pointer to member with a reference_wrapper + // as the object expression + template struct reference_wrapper; + + template + struct __result_of_memobj<_Res _Class::*, reference_wrapper<_Arg>> + : __result_of_memobj<_Res _Class::*, _Arg> + { + typedef typename + __result_of_memobj_ref<_Res _Class::*, _Arg&>::type type; + }; + + template + struct __result_of_memobj<_Res _Class::*, reference_wrapper<_Arg>&> + : __result_of_memobj<_Res _Class::*, reference_wrapper<_Arg>> + { }; + + template + struct __result_of_memobj<_Res _Class::*, reference_wrapper<_Arg>&&> + : __result_of_memobj<_Res _Class::*, reference_wrapper<_Arg>> + { }; + + template + struct __result_of_memfun<_Res _Class::*, reference_wrapper<_Arg>, _Args...> + : __result_of_memfun<_Res _Class::*, _Arg&, _Args...> + { + typedef typename + __result_of_memfun_ref<_Res _Class::*, _Arg&, _Args...>::type type; + }; + + template + struct __result_of_memfun<_Res _Class::*, reference_wrapper<_Arg>&, + _Args...> + : __result_of_memfun<_Res _Class::*, reference_wrapper<_Arg>, _Args...> + { }; + + template + struct __result_of_memfun<_Res _Class::*, reference_wrapper<_Arg>&&, + _Args...> + : __result_of_memfun<_Res _Class::*, reference_wrapper<_Arg>, _Args...> + { }; + template struct __result_of_impl { @@ -2347,9 +2401,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __result_of_other_impl { template - static __success_type()(std::declval<_Args>()...) - )> _S_test(int); + ), __invoke_other> _S_test(int); template static __failure_type _S_test(...); diff --git a/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc b/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc index 73eabf90a9d..a09788a29e0 100644 --- a/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc +++ b/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc @@ -30,10 +30,6 @@ void test01() { const int dummy = 0; std::bind(&inc, _1)(0); // { dg-error "no match" } - // { dg-error "rvalue|const" "" { target *-*-* } 1125 } - // { dg-error "rvalue|const" "" { target *-*-* } 1139 } - // { dg-error "rvalue|const" "" { target *-*-* } 1153 } - // { dg-error "rvalue|const" "" { target *-*-* } 1167 } std::bind(&inc, std::ref(dummy))(); // { dg-error "no match" } } @@ -50,8 +46,15 @@ void test02() const int dummy = 0; std::bind(Inc(), _1)(dummy); // { dg-error "no match" } std::bind(&Inc::f, Inc(), std::ref(dummy))(); // { dg-error "no match" } + // { dg-error "no match" "" { target *-*-* } 594 } + // { dg-error "no type" "" { target *-*-* } 237 } } +// { dg-error "rvalue|const" "" { target *-*-* } 1024 } +// { dg-error "rvalue|const" "" { target *-*-* } 1038 } +// { dg-error "rvalue|const" "" { target *-*-* } 1052 } +// { dg-error "rvalue|const" "" { target *-*-* } 1066 } + int main() { test01(); diff --git a/libstdc++-v3/testsuite/20_util/function_objects/mem_fn/55463.cc b/libstdc++-v3/testsuite/20_util/function_objects/mem_fn/55463.cc index 2eba90229c7..c67731ae2bc 100644 --- a/libstdc++-v3/testsuite/20_util/function_objects/mem_fn/55463.cc +++ b/libstdc++-v3/testsuite/20_util/function_objects/mem_fn/55463.cc @@ -98,15 +98,3 @@ void test01() int& pval __attribute__((unused)) = std::mem_fn( &X::data )( X_ptr() ); int& sval __attribute__((unused)) = std::mem_fn( &X::data )( smart_ptr() ); } - -void test02() -{ - std::reference_wrapper r = ref(); - X& x1 __attribute__((unused)) - = std::mem_fn( &std::reference_wrapper::get )( r ); - const std::reference_wrapper cr = ref(); - const X& x3 __attribute__((unused)) - = std::mem_fn( &std::reference_wrapper::get )( cr ); - X& x2 __attribute__((unused)) - = std::mem_fn( &std::reference_wrapper::get )( ref() ); -}