From 8d9076969b94fe6ed2a7bb3e19b56f3c2ac9488c Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Mon, 3 Nov 2014 02:55:32 +0000 Subject: [PATCH] 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. From-SVN: r217024 --- libstdc++-v3/ChangeLog | 11 + libstdc++-v3/include/std/functional | 462 +++++++----------- .../function_objects/mem_fn/refqual.cc | 34 ++ 3 files changed, 223 insertions(+), 284 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/function_objects/mem_fn/refqual.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index d24f3a3e9a5..86bc08fe3cc 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,14 @@ +2014-11-02 Jonathan Wakely + + 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. + 2014-10-31 Jonathan Wakely * include/bits/stl_bvector.h (_Bvector_base): Use allocator_traits. diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index 5bc2730c2f5..ecc5bc98f05 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 00000000000..35a66e55410 --- /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) ); +} -- 2.30.2