From patchwork Mon Nov 3 02:56:01 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 406006 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 136F914008C for ; Mon, 3 Nov 2014 13:56:24 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=ndHQ5NvPAVsFjIzFCWj8VHVb2KRzHBb8cdZb8yh1jU2x0YrYth3HA TaTAj0QxDidgfh7+EdE4R/yUuvKjuleW+nnlC+xeVdEA2323kTE7TUR7hBgm2mn8 IDymKDJ0t+mFyKLcWug0/t/a5gPzQ6TcE2d2zcWg9LjrlEF7hw0tgg= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=TFS4R+i8tgwm9C8lZPd09EAczZA=; b=VPCAU77OKbFc6EmhFyL9 Le4br4QCylZCPtubxu27YA+S3cD3MuN8H9Uca58q1YF/tvFoXmctrsme9sRX/Tdp 6VTV/6pXGmAfjLKG3W58Wbw8m8Kl7bUyQvIX2mAF28DhtJXjQqRbftkph0UGfQPU 16pUEFPTvuiWDbkqSkcwRys= Received: (qmail 13205 invoked by alias); 3 Nov 2014 02:56:13 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 13161 invoked by uid 89); 3 Nov 2014 02:56:08 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.4 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD, SPF_HELO_PASS, SPF_PASS, T_FILL_THIS_FORM_SHORT autolearn=ham version=3.3.2 X-Spam-User: qpsmtpd, 2 recipients X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Mon, 03 Nov 2014 02:56:05 +0000 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id sA32u3N1000824 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Sun, 2 Nov 2014 21:56:03 -0500 Received: from localhost (ovpn-116-33.ams2.redhat.com [10.36.116.33]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id sA32u1f9022006; Sun, 2 Nov 2014 21:56:02 -0500 Date: Mon, 3 Nov 2014 02:56:01 +0000 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [patch] libstdc++/57898 add ref-qualifier support to std::mem_fn Message-ID: <20141103025601.GA3961@redhat.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.23 (2014-03-12) Two patches, the first rewrites std::mem_fn to support ref-qualifiers (without tons of code duplication) and the second adds some static assertions to reject invalid bind expressions earlier (at "bind time") Tested x86_64-linux, committed to trunk. commit 9e8b41f93b5d3e6f9578fbfe9bccd7ae691733ea Author: Jonathan Wakely Date: Sun Nov 2 18:35:49 2014 +0000 Check number of arguments in bind expressions. * include/std/functional (_Mem_fn_traits_base::__arity): New typedef. (_Mem_fn_base::_Arity): New typedef. (_Bind_check_arity): New class template. (_Bind_helper, _Bindres_helper, _Bind_simple_helper): Check arity. * testsuite/20_util/bind/ref_neg.cc: Adjust dg-error. diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index ecc5bc9..f615ae4 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -515,6 +515,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) using __arg_types = _Pack<_ArgTypes...>; using __maybe_type = _Maybe_unary_or_binary_function<_Res, _Class*, _ArgTypes...>; + using __arity = integral_constant; }; template @@ -634,6 +635,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) public: using result_type = typename _Traits::__result_type; + using _Arity = typename _Traits::__arity; private: using _Class = typename _Traits::__class_type; @@ -755,6 +757,8 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) { return (*__ptr).*_M_pm; } public: + using _Arity = integral_constant; + explicit _Mem_fn_base(_Res _Class::*__pm) noexcept : _M_pm(__pm) { } @@ -1485,6 +1489,24 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) struct is_bind_expression> : public true_type { }; + template + struct _Bind_check_arity { }; + + template + struct _Bind_check_arity<_Ret (*)(_Args...), _BoundArgs...> + { + static_assert(sizeof...(_BoundArgs) == sizeof...(_Args), + "Wrong number of arguments for function"); + }; + + template + struct _Bind_check_arity<_Tp _Class::*, _BoundArgs...> + { + using _Arity = typename _Mem_fn<_Tp _Class::*>::_Arity; + static_assert(sizeof...(_BoundArgs) == _Arity::value + 1, + "Wrong number of arguments for pointer-to-member"); + }; + // Trait type used to remove std::bind() from overload set via SFINAE // when first argument has integer type, so that std::bind() will // not be a better match than ::bind() from the BSD Sockets API. @@ -1493,6 +1515,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) template struct _Bind_helper + : _Bind_check_arity::type, _BoundArgs...> { typedef _Maybe_wrap_member_pointer::type> __maybe_type; @@ -1525,6 +1548,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) template struct _Bindres_helper + : _Bind_check_arity::type, _BoundArgs...> { typedef _Maybe_wrap_member_pointer::type> __maybe_type; @@ -1599,6 +1623,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) template struct _Bind_simple_helper + : _Bind_check_arity::type, _BoundArgs...> { typedef _Maybe_wrap_member_pointer::type> __maybe_type; diff --git a/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc b/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc index 6b315c1..1063dd3 100644 --- a/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc +++ b/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc @@ -30,10 +30,10 @@ void test01() { const int dummy = 0; std::bind(&inc, _1)(0); // { dg-error "no match" } - // { dg-error "rvalue|const" "" { target *-*-* } 1315 } - // { dg-error "rvalue|const" "" { target *-*-* } 1329 } - // { dg-error "rvalue|const" "" { target *-*-* } 1343 } - // { dg-error "rvalue|const" "" { target *-*-* } 1357 } + // { dg-error "rvalue|const" "" { target *-*-* } 1213 } + // { dg-error "rvalue|const" "" { target *-*-* } 1227 } + // { dg-error "rvalue|const" "" { target *-*-* } 1241 } + // { dg-error "rvalue|const" "" { target *-*-* } 1255 } std::bind(&inc, std::ref(dummy))(); // { dg-error "no match" } } commit 5ab949c9590fc837118f8ad6d0facc3f8bd2cc07 Author: Jonathan Wakely Date: Wed Nov 28 00:58:58 2012 +0000 Add support for ref-qualified functions to std::mem_fn PR libstdc++/57898 * include/std/functional (_Mem_fn_traits_base): New class template. (_Mem_fn_traits): New class template with specializations for every combination of cv-qualified and ref-qualified member function. (_Mem_fn_base): New class template for all pointer to member function types and partial specialization for pointer to member object types. (_Mem_fn): Inherit from _Mem_fn_base. * testsuite/20_util/function_objects/mem_fn/refqual.cc: New. diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index 5bc2730..ecc5bc9 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -504,344 +504,231 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) struct _Maybe_unary_or_binary_function<_Res, _T1, _T2> : std::binary_function<_T1, _T2, _Res> { }; - /// Implementation of @c mem_fn for member function pointers. + template + struct _Mem_fn_traits; + template - class _Mem_fn<_Res (_Class::*)(_ArgTypes...)> - : public _Maybe_unary_or_binary_function<_Res, _Class*, _ArgTypes...> + struct _Mem_fn_traits_base { - typedef _Res (_Class::*_Functor)(_ArgTypes...); - - template - _Res - _M_call(_Tp&& __object, const volatile _Class *, - _Args&&... __args) const - { - return (std::forward<_Tp>(__object).*__pmf) - (std::forward<_Args>(__args)...); - } - - template - _Res - _M_call(_Tp&& __ptr, const volatile void *, _Args&&... __args) const - { return ((*__ptr).*__pmf)(std::forward<_Args>(__args)...); } - - // Require each _Args to be convertible to corresponding _ArgTypes - template - using _RequireValidArgs - = _Require<_AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; - - // Require each _Args to be convertible to corresponding _ArgTypes - // and require _Tp is not _Class, _Class& or _Class* - template - using _RequireValidArgs2 - = _Require<_NotSame<_Class, _Tp>, _NotSame<_Class*, _Tp>, - _AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; - - // Require each _Args to be convertible to corresponding _ArgTypes - // and require _Tp is _Class or derived from _Class - template - using _RequireValidArgs3 - = _Require, - _AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; - - public: - typedef _Res result_type; - - explicit _Mem_fn(_Functor __pmf) : __pmf(__pmf) { } - - // Handle objects - template> - _Res - operator()(_Class& __object, _Args&&... __args) const - { return (__object.*__pmf)(std::forward<_Args>(__args)...); } - - template> - _Res - operator()(_Class&& __object, _Args&&... __args) const - { - return (std::move(__object).*__pmf)(std::forward<_Args>(__args)...); - } - - // Handle pointers - template> - _Res - operator()(_Class* __object, _Args&&... __args) const - { return (__object->*__pmf)(std::forward<_Args>(__args)...); } - - // Handle smart pointers, references and pointers to derived - template> - _Res - operator()(_Tp&& __object, _Args&&... __args) const - { - return _M_call(std::forward<_Tp>(__object), &__object, - std::forward<_Args>(__args)...); - } - - template> - _Res - operator()(reference_wrapper<_Tp> __ref, _Args&&... __args) const - { return operator()(__ref.get(), std::forward<_Args>(__args)...); } - - private: - _Functor __pmf; + using __result_type = _Res; + using __class_type = _Class; + using __arg_types = _Pack<_ArgTypes...>; + using __maybe_type + = _Maybe_unary_or_binary_function<_Res, _Class*, _ArgTypes...>; }; - /// Implementation of @c mem_fn for const member function pointers. template - class _Mem_fn<_Res (_Class::*)(_ArgTypes...) const> - : public _Maybe_unary_or_binary_function<_Res, const _Class*, - _ArgTypes...> + struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...)> + : _Mem_fn_traits_base<_Res, _Class, _ArgTypes...> { - typedef _Res (_Class::*_Functor)(_ArgTypes...) const; - - template - _Res - _M_call(_Tp&& __object, const volatile _Class *, - _Args&&... __args) const - { - return (std::forward<_Tp>(__object).*__pmf) - (std::forward<_Args>(__args)...); - } - - template - _Res - _M_call(_Tp&& __ptr, const volatile void *, _Args&&... __args) const - { return ((*__ptr).*__pmf)(std::forward<_Args>(__args)...); } - - template - using _RequireValidArgs - = _Require<_AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; - - template - using _RequireValidArgs2 - = _Require<_NotSame<_Class, _Tp>, _NotSame, - _AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; - - template - using _RequireValidArgs3 - = _Require, - _AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; - - public: - typedef _Res result_type; + using __pmf_type = _Res (_Class::*)(_ArgTypes...); + using __lvalue = true_type; + using __rvalue = true_type; + }; - explicit _Mem_fn(_Functor __pmf) : __pmf(__pmf) { } + template + struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) const> + : _Mem_fn_traits_base<_Res, const _Class, _ArgTypes...> + { + using __pmf_type = _Res (_Class::*)(_ArgTypes...) const; + using __lvalue = true_type; + using __rvalue = true_type; + }; - // Handle objects - template> - _Res - operator()(const _Class& __object, _Args&&... __args) const - { return (__object.*__pmf)(std::forward<_Args>(__args)...); } - - template> - _Res - operator()(const _Class&& __object, _Args&&... __args) const - { - return (std::move(__object).*__pmf)(std::forward<_Args>(__args)...); - } + template + struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) volatile> + : _Mem_fn_traits_base<_Res, volatile _Class, _ArgTypes...> + { + using __pmf_type = _Res (_Class::*)(_ArgTypes...) volatile; + using __lvalue = true_type; + using __rvalue = true_type; + }; - // Handle pointers - template> - _Res - operator()(const _Class* __object, _Args&&... __args) const - { return (__object->*__pmf)(std::forward<_Args>(__args)...); } + template + struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) const volatile> + : _Mem_fn_traits_base<_Res, const volatile _Class, _ArgTypes...> + { + using __pmf_type = _Res (_Class::*)(_ArgTypes...) const volatile; + using __lvalue = true_type; + using __rvalue = true_type; + }; - // Handle smart pointers, references and pointers to derived - template> - _Res operator()(_Tp&& __object, _Args&&... __args) const - { - return _M_call(std::forward<_Tp>(__object), &__object, - std::forward<_Args>(__args)...); - } + template + struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...)&> + : _Mem_fn_traits_base<_Res, _Class, _ArgTypes...> + { + using __pmf_type = _Res (_Class::*)(_ArgTypes...)&; + using __lvalue = true_type; + using __rvalue = false_type; + }; - template> - _Res - operator()(reference_wrapper<_Tp> __ref, _Args&&... __args) const - { return operator()(__ref.get(), std::forward<_Args>(__args)...); } + template + struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) const&> + : _Mem_fn_traits_base<_Res, const _Class, _ArgTypes...> + { + using __pmf_type = _Res (_Class::*)(_ArgTypes...) const&; + using __lvalue = true_type; + using __rvalue = false_type; + }; - private: - _Functor __pmf; + template + struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) volatile&> + : _Mem_fn_traits_base<_Res, volatile _Class, _ArgTypes...> + { + using __pmf_type = _Res (_Class::*)(_ArgTypes...) volatile&; + using __lvalue = true_type; + using __rvalue = false_type; }; - /// Implementation of @c mem_fn for volatile member function pointers. template - class _Mem_fn<_Res (_Class::*)(_ArgTypes...) volatile> - : public _Maybe_unary_or_binary_function<_Res, volatile _Class*, - _ArgTypes...> + struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) const volatile&> + : _Mem_fn_traits_base<_Res, const volatile _Class, _ArgTypes...> { - typedef _Res (_Class::*_Functor)(_ArgTypes...) volatile; + using __pmf_type = _Res (_Class::*)(_ArgTypes...) const volatile&; + using __lvalue = true_type; + using __rvalue = false_type; + }; - template - _Res - _M_call(_Tp&& __object, const volatile _Class *, - _Args&&... __args) const - { - return (std::forward<_Tp>(__object).*__pmf) - (std::forward<_Args>(__args)...); - } + template + struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...)&&> + : _Mem_fn_traits_base<_Res, _Class, _ArgTypes...> + { + using __pmf_type = _Res (_Class::*)(_ArgTypes...)&&; + using __lvalue = false_type; + using __rvalue = true_type; + }; - template - _Res - _M_call(_Tp&& __ptr, const volatile void *, _Args&&... __args) const - { return ((*__ptr).*__pmf)(std::forward<_Args>(__args)...); } + template + struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) const&&> + : _Mem_fn_traits_base<_Res, const _Class, _ArgTypes...> + { + using __pmf_type = _Res (_Class::*)(_ArgTypes...) const&&; + using __lvalue = false_type; + using __rvalue = true_type; + }; - template - using _RequireValidArgs - = _Require<_AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; + template + struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) volatile&&> + : _Mem_fn_traits_base<_Res, volatile _Class, _ArgTypes...> + { + using __pmf_type = _Res (_Class::*)(_ArgTypes...) volatile&&; + using __lvalue = false_type; + using __rvalue = true_type; + }; - template - using _RequireValidArgs2 - = _Require<_NotSame<_Class, _Tp>, _NotSame, - _AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; + template + struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) const volatile&&> + : _Mem_fn_traits_base<_Res, const volatile _Class, _ArgTypes...> + { + using __pmf_type = _Res (_Class::*)(_ArgTypes...) const volatile&&; + using __lvalue = false_type; + using __rvalue = true_type; + }; - template - using _RequireValidArgs3 - = _Require, - _AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; + template::value> + class _Mem_fn_base + : public _Mem_fn_traits<_MemFunPtr>::__maybe_type + { + using _Traits = _Mem_fn_traits<_MemFunPtr>; public: - typedef _Res result_type; - - explicit _Mem_fn(_Functor __pmf) : __pmf(__pmf) { } - - // Handle objects - template> - _Res - operator()(volatile _Class& __object, _Args&&... __args) const - { return (__object.*__pmf)(std::forward<_Args>(__args)...); } - - template> - _Res - operator()(volatile _Class&& __object, _Args&&... __args) const - { - return (std::move(__object).*__pmf)(std::forward<_Args>(__args)...); - } - - // Handle pointers - template> - _Res - operator()(volatile _Class* __object, _Args&&... __args) const - { return (__object->*__pmf)(std::forward<_Args>(__args)...); } - - // Handle smart pointers, references and pointers to derived - template> - _Res - operator()(_Tp&& __object, _Args&&... __args) const - { - return _M_call(std::forward<_Tp>(__object), &__object, - std::forward<_Args>(__args)...); - } - - template> - _Res - operator()(reference_wrapper<_Tp> __ref, _Args&&... __args) const - { return operator()(__ref.get(), std::forward<_Args>(__args)...); } + using result_type = typename _Traits::__result_type; private: - _Functor __pmf; - }; - - /// Implementation of @c mem_fn for const volatile member function pointers. - template - class _Mem_fn<_Res (_Class::*)(_ArgTypes...) const volatile> - : public _Maybe_unary_or_binary_function<_Res, const volatile _Class*, - _ArgTypes...> - { - typedef _Res (_Class::*_Functor)(_ArgTypes...) const volatile; + using _Class = typename _Traits::__class_type; + using _ArgTypes = typename _Traits::__arg_types; + using _Pmf = typename _Traits::__pmf_type; template - _Res + result_type _M_call(_Tp&& __object, const volatile _Class *, _Args&&... __args) const { - return (std::forward<_Tp>(__object).*__pmf) + return (std::forward<_Tp>(__object).*_M_pmf) (std::forward<_Args>(__args)...); } template - _Res + result_type _M_call(_Tp&& __ptr, const volatile void *, _Args&&... __args) const - { return ((*__ptr).*__pmf)(std::forward<_Args>(__args)...); } + { return ((*__ptr).*_M_pmf)(std::forward<_Args>(__args)...); } + // Require each _Args to be convertible to corresponding _ArgTypes template using _RequireValidArgs - = _Require<_AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; + = _Require<_AllConvertible<_Pack<_Args...>, _ArgTypes>>; + // Require each _Args to be convertible to corresponding _ArgTypes + // and require _Tp is not _Class, _Class& or _Class* template using _RequireValidArgs2 - = _Require<_NotSame<_Class, _Tp>, - _NotSame, - _AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; + = _Require<_NotSame<_Class, _Tp>, _NotSame<_Class*, _Tp>, + _AllConvertible<_Pack<_Args...>, _ArgTypes>>; + // Require each _Args to be convertible to corresponding _ArgTypes + // and require _Tp is _Class or derived from _Class template using _RequireValidArgs3 = _Require, - _AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; + _AllConvertible<_Pack<_Args...>, _ArgTypes>>; public: - typedef _Res result_type; - - explicit _Mem_fn(_Functor __pmf) : __pmf(__pmf) { } + explicit _Mem_fn_base(_Pmf __pmf) : _M_pmf(__pmf) { } // Handle objects - template> - _Res - operator()(const volatile _Class& __object, _Args&&... __args) const - { return (__object.*__pmf)(std::forward<_Args>(__args)...); } - - template> - _Res - operator()(const volatile _Class&& __object, _Args&&... __args) const + template, _ArgTypes>>> + result_type + operator()(_Class& __object, _Args&&... __args) const + { return (__object.*_M_pmf)(std::forward<_Args>(__args)...); } + + template, _ArgTypes>>> + result_type + operator()(_Class&& __object, _Args&&... __args) const { - return (std::move(__object).*__pmf)(std::forward<_Args>(__args)...); + return (std::move(__object).*_M_pmf)(std::forward<_Args>(__args)...); } // Handle pointers - template> - _Res - operator()(const volatile _Class* __object, _Args&&... __args) const - { return (__object->*__pmf)(std::forward<_Args>(__args)...); } + template, _ArgTypes>>> + 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> - _Res operator()(_Tp&& __object, _Args&&... __args) const + // TODO how to constrain to lvalue/rvalue here? constrain _M_call? + template, _NotSame<_Class*, _Tp>, + _AllConvertible<_Pack<_Args...>, _ArgTypes>>> + result_type + operator()(_Tp&& __object, _Args&&... __args) const { return _M_call(std::forward<_Tp>(__object), &__object, std::forward<_Args>(__args)...); } - template> - _Res + // Handle reference wrappers + template, + typename _Traits::__lvalue, + _AllConvertible<_Pack<_Args...>, _ArgTypes>>> + result_type operator()(reference_wrapper<_Tp> __ref, _Args&&... __args) const { return operator()(__ref.get(), std::forward<_Args>(__args)...); } private: - _Functor __pmf; - }; - - - template - struct _Mem_fn_const_or_non - { - typedef const _Tp& type; - }; - - template - struct _Mem_fn_const_or_non<_Tp, false> - { - typedef _Tp& type; + _Pmf _M_pmf; }; + // Partial specialization for member object pointers. template - class _Mem_fn<_Res _Class::*> + class _Mem_fn_base<_Res _Class::*, false> { using __pm_type = _Res _Class::*; @@ -852,56 +739,56 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) auto _M_call(_Tp&& __object, const _Class *) const noexcept -> decltype(std::forward<_Tp>(__object).*std::declval<__pm_type&>()) - { return std::forward<_Tp>(__object).*__pm; } + { 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)).*__pm; } + { 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).*__pm; } + { return (*__ptr).*_M_pm; } public: explicit - _Mem_fn(_Res _Class::*__pm) noexcept : __pm(__pm) { } + _Mem_fn_base(_Res _Class::*__pm) noexcept : _M_pm(__pm) { } // Handle objects _Res& operator()(_Class& __object) const noexcept - { return __object.*__pm; } + { return __object.*_M_pm; } const _Res& operator()(const _Class& __object) const noexcept - { return __object.*__pm; } + { return __object.*_M_pm; } _Res&& operator()(_Class&& __object) const noexcept - { return std::forward<_Class>(__object).*__pm; } + { return std::forward<_Class>(__object).*_M_pm; } const _Res&& operator()(const _Class&& __object) const noexcept - { return std::forward(__object).*__pm; } + { return std::forward(__object).*_M_pm; } // Handle pointers _Res& operator()(_Class* __object) const noexcept - { return __object->*__pm; } + { return __object->*_M_pm; } const _Res& operator()(const _Class* __object) const noexcept - { return __object->*__pm; } + { return __object->*_M_pm; } // Handle smart pointers and derived template>> auto operator()(_Tp&& __unknown) const - noexcept(noexcept(std::declval<_Mem_fn*>()->_M_call + 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); } @@ -909,12 +796,19 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) template>> auto operator()(reference_wrapper<_Tp> __ref) const - noexcept(noexcept(std::declval<_Mem_fn&>()(__ref.get()))) + noexcept(noexcept(std::declval<_Mem_fn_base&>()(__ref.get()))) -> decltype((*this)(__ref.get())) { return (*this)(__ref.get()); } private: - _Res _Class::*__pm; + _Res _Class::*_M_pm; + }; + + template + struct _Mem_fn<_Res _Class::*> + : _Mem_fn_base<_Res _Class::*> + { + using _Mem_fn_base<_Res _Class::*>::_Mem_fn_base; }; // _GLIBCXX_RESOLVE_LIB_DEFECTS diff --git a/libstdc++-v3/testsuite/20_util/function_objects/mem_fn/refqual.cc b/libstdc++-v3/testsuite/20_util/function_objects/mem_fn/refqual.cc new file mode 100644 index 0000000..35a66e5 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/function_objects/mem_fn/refqual.cc @@ -0,0 +1,34 @@ +// Copyright (C) 2014 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 +// . + +// { dg-options "-std=gnu++11" } +// { dg-do compile } + +#include + +struct Foo +{ + void r()&& { } + int l() const& { return 0; } +}; + +void test01() +{ + Foo f; + int i = std::mem_fn(&Foo::l)( f ); + std::mem_fn(&Foo::r)( std::move(f) ); +}