My attempt to implement LWG 2219 wasn't very good and resulted in ambiguous overloads for the testcase in PR 59768. This fixes it, and makes sure that const reference_wrappers can be used too.
Tested powerpc64le-linux, committed to trunk.
commit 9082b4be70fe2e4993ae0c765608fcd8da544bc5 Author: Jonathan Wakely <jwak...@redhat.com> Date: Fri Dec 11 19:46:49 2015 +0000 Fix std::invoke support for reference_wrappers PR libstdc++/59768 * include/std/functional (_Unwrap, __invfwd): Define. (__invoke_impl): Remove reference_wrapper overloads and use __invfwd. * include/std/type_traits (__result_of_memobj, __result_of_memfun): Add partial specializations for const reference_wrappers and simplify. * testsuite/20_util/bind/ref_neg.cc: Use dg-excess-errors. * testsuite/20_util/function_objects/invoke/59768.cc: New. diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index f1dc839..19caa96 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -184,6 +184,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : _Weak_result_type_impl<typename remove_cv<_Functor>::type> { }; + template<typename _Tp, typename _Up = typename decay<_Tp>::type> + struct _Unwrap + { + using type = _Tp&&; + + // Equivalent to std::forward<_Tp> + static constexpr _Tp&& + _S_fwd(_Tp& __t) noexcept { return static_cast<_Tp&&>(__t); } + }; + + template<typename _Tp, typename _Up> + struct _Unwrap<_Tp, reference_wrapper<_Up>> + { + using type = _Up&; + + // Get an lvalue-reference from a reference_wrapper. + static _Up& + _S_fwd(const _Tp& __t) noexcept { __t.get(); } + }; + + // Used by __invoke_impl instead of std::forward<_Tp> so that a + // reference_wrapper is converted to an lvalue-reference. + template<typename _Tp> + typename _Unwrap<_Tp>::type + __invfwd(typename remove_reference<_Tp>::type& __t) noexcept + { return _Unwrap<_Tp>::_S_fwd(__t); } + template<typename _Res, typename _Fn, typename... _Args> inline _Res __invoke_impl(__invoke_other, _Fn&& __f, _Args&&... __args) @@ -194,15 +221,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION 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<typename _Res, typename _MemFun, typename _Tp, typename... _Args> - 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)...); } + noexcept(noexcept((__invfwd<_Tp>(__t).*__f)(forward<_Args>(__args)...))) + { return (__invfwd<_Tp>(__t).*__f)(forward<_Args>(__args)...); } template<typename _Res, typename _MemFun, typename _Tp, typename... _Args> inline _Res @@ -214,15 +234,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Res, typename _MemFun, typename _Tp, typename... _Args> inline _Res __invoke_impl(__invoke_memobj_ref, _MemFun&& __f, _Tp&& __t) - noexcept(noexcept(forward<_Tp>(__t).*__f)) - { return forward<_Tp>(__t).*__f; } - - template<typename _Res, typename _MemFun, typename _Tp, typename... _Args> - inline _Res - __invoke_impl(__invoke_memobj_ref, _MemFun&& __f, - reference_wrapper<_Tp> __t) - noexcept(noexcept(__t.get().*__f)) - { return __t.get().*__f; } + noexcept(noexcept(__invfwd<_Tp>(__t).*__f)) + { return __invfwd<_Tp>(__t).*__f; } template<typename _Res, typename _MemFun, typename _Tp, typename... _Args> inline _Res diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index e5102de..5b4d073 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -2391,44 +2391,59 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // _GLIBCXX_RESOLVE_LIB_DEFECTS // 2219. INVOKE-ing a pointer to member with a reference_wrapper // as the object expression - template<typename> struct reference_wrapper; template<typename _Res, typename _Class, typename _Arg> 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; - }; + : __result_of_memobj_ref<_Res _Class::*, _Arg&> + { }; template<typename _Res, typename _Class, typename _Arg> struct __result_of_memobj<_Res _Class::*, reference_wrapper<_Arg>&> - : __result_of_memobj<_Res _Class::*, reference_wrapper<_Arg>> + : __result_of_memobj_ref<_Res _Class::*, _Arg&> + { }; + + template<typename _Res, typename _Class, typename _Arg> + struct __result_of_memobj<_Res _Class::*, const reference_wrapper<_Arg>&> + : __result_of_memobj_ref<_Res _Class::*, _Arg&> { }; template<typename _Res, typename _Class, typename _Arg> struct __result_of_memobj<_Res _Class::*, reference_wrapper<_Arg>&&> - : __result_of_memobj<_Res _Class::*, reference_wrapper<_Arg>> + : __result_of_memobj_ref<_Res _Class::*, _Arg&> + { }; + + template<typename _Res, typename _Class, typename _Arg> + struct __result_of_memobj<_Res _Class::*, const reference_wrapper<_Arg>&&> + : __result_of_memobj_ref<_Res _Class::*, _Arg&> { }; template<typename _Res, typename _Class, typename _Arg, typename... _Args> 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; - }; + : __result_of_memfun_ref<_Res _Class::*, _Arg&, _Args...> + { }; template<typename _Res, typename _Class, typename _Arg, typename... _Args> struct __result_of_memfun<_Res _Class::*, reference_wrapper<_Arg>&, _Args...> - : __result_of_memfun<_Res _Class::*, reference_wrapper<_Arg>, _Args...> + : __result_of_memfun_ref<_Res _Class::*, _Arg&, _Args...> + { }; + + template<typename _Res, typename _Class, typename _Arg, typename... _Args> + struct __result_of_memfun<_Res _Class::*, const reference_wrapper<_Arg>&, + _Args...> + : __result_of_memfun_ref<_Res _Class::*, _Arg&, _Args...> { }; template<typename _Res, typename _Class, typename _Arg, typename... _Args> struct __result_of_memfun<_Res _Class::*, reference_wrapper<_Arg>&&, _Args...> - : __result_of_memfun<_Res _Class::*, reference_wrapper<_Arg>, _Args...> + : __result_of_memfun_ref<_Res _Class::*, _Arg&, _Args...> + { }; + + template<typename _Res, typename _Class, typename _Arg, typename... _Args> + struct __result_of_memfun<_Res _Class::*, const reference_wrapper<_Arg>&&, + _Args...> + : __result_of_memfun_ref<_Res _Class::*, _Arg&, _Args...> { }; template<bool, bool, typename _Functor, typename... _ArgTypes> diff --git a/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc b/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc index a09788a..d1edfbf 100644 --- a/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc +++ b/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc @@ -46,14 +46,9 @@ 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 } +// { dg-excess-errors "reasons for deduction/substitution failures" } int main() { diff --git a/libstdc++-v3/testsuite/20_util/function_objects/invoke/59768.cc b/libstdc++-v3/testsuite/20_util/function_objects/invoke/59768.cc new file mode 100644 index 0000000..44f1418 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/function_objects/invoke/59768.cc @@ -0,0 +1,43 @@ +// Copyright (C) 2015 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++1z" } +// { dg-do compile } + +#include <functional> + +struct A { + void foo(int n) { } +}; + +void +test01() +{ + A a; + auto ref = std::ref(a); + std::invoke(&A::foo, ref, 100); // lvalue + std::invoke(&A::foo, std::move(ref), 100); // rvalue + const auto refc = std::ref(a); + std::invoke(&A::foo, refc, 100); // const lvalue + std::invoke(&A::foo, std::move(refc), 100); // const rvalue +} + +int +main() +{ + test01(); +}