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 5ab949c9590fc837118f8ad6d0facc3f8bd2cc07 Author: Jonathan Wakely <jwakely....@gmail.com> 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<typename _Signature> + struct _Mem_fn_traits; + template<typename _Res, typename _Class, typename... _ArgTypes> - 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<typename _Tp, typename... _Args> - _Res - _M_call(_Tp&& __object, const volatile _Class *, - _Args&&... __args) const - { - return (std::forward<_Tp>(__object).*__pmf) - (std::forward<_Args>(__args)...); - } - - template<typename _Tp, typename... _Args> - _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<typename... _Args> - 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<typename _Tp, typename... _Args> - 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<typename _Tp, typename... _Args> - using _RequireValidArgs3 - = _Require<is_base_of<_Class, _Tp>, - _AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; - - public: - typedef _Res result_type; - - explicit _Mem_fn(_Functor __pmf) : __pmf(__pmf) { } - - // Handle objects - template<typename... _Args, typename _Req = _RequireValidArgs<_Args...>> - _Res - operator()(_Class& __object, _Args&&... __args) const - { return (__object.*__pmf)(std::forward<_Args>(__args)...); } - - template<typename... _Args, typename _Req = _RequireValidArgs<_Args...>> - _Res - operator()(_Class&& __object, _Args&&... __args) const - { - return (std::move(__object).*__pmf)(std::forward<_Args>(__args)...); - } - - // Handle pointers - template<typename... _Args, typename _Req = _RequireValidArgs<_Args...>> - _Res - operator()(_Class* __object, _Args&&... __args) const - { return (__object->*__pmf)(std::forward<_Args>(__args)...); } - - // Handle smart pointers, references and pointers to derived - template<typename _Tp, typename... _Args, - typename _Req = _RequireValidArgs2<_Tp, _Args...>> - _Res - operator()(_Tp&& __object, _Args&&... __args) const - { - return _M_call(std::forward<_Tp>(__object), &__object, - std::forward<_Args>(__args)...); - } - - template<typename _Tp, typename... _Args, - typename _Req = _RequireValidArgs3<_Tp, _Args...>> - _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<typename _Res, typename _Class, typename... _ArgTypes> - 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<typename _Tp, typename... _Args> - _Res - _M_call(_Tp&& __object, const volatile _Class *, - _Args&&... __args) const - { - return (std::forward<_Tp>(__object).*__pmf) - (std::forward<_Args>(__args)...); - } - - template<typename _Tp, typename... _Args> - _Res - _M_call(_Tp&& __ptr, const volatile void *, _Args&&... __args) const - { return ((*__ptr).*__pmf)(std::forward<_Args>(__args)...); } - - template<typename... _Args> - using _RequireValidArgs - = _Require<_AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; - - template<typename _Tp, typename... _Args> - using _RequireValidArgs2 - = _Require<_NotSame<_Class, _Tp>, _NotSame<const _Class*, _Tp>, - _AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; - - template<typename _Tp, typename... _Args> - using _RequireValidArgs3 - = _Require<is_base_of<_Class, _Tp>, - _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<typename _Res, typename _Class, typename... _ArgTypes> + 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<typename... _Args, typename _Req = _RequireValidArgs<_Args...>> - _Res - operator()(const _Class& __object, _Args&&... __args) const - { return (__object.*__pmf)(std::forward<_Args>(__args)...); } - - template<typename... _Args, typename _Req = _RequireValidArgs<_Args...>> - _Res - operator()(const _Class&& __object, _Args&&... __args) const - { - return (std::move(__object).*__pmf)(std::forward<_Args>(__args)...); - } + template<typename _Res, typename _Class, typename... _ArgTypes> + 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<typename... _Args, typename _Req = _RequireValidArgs<_Args...>> - _Res - operator()(const _Class* __object, _Args&&... __args) const - { return (__object->*__pmf)(std::forward<_Args>(__args)...); } + template<typename _Res, typename _Class, typename... _ArgTypes> + 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<typename _Tp, typename... _Args, - typename _Req = _RequireValidArgs2<_Tp, _Args...>> - _Res operator()(_Tp&& __object, _Args&&... __args) const - { - return _M_call(std::forward<_Tp>(__object), &__object, - std::forward<_Args>(__args)...); - } + template<typename _Res, typename _Class, typename... _ArgTypes> + 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<typename _Tp, typename... _Args, - typename _Req = _RequireValidArgs3<_Tp, _Args...>> - _Res - operator()(reference_wrapper<_Tp> __ref, _Args&&... __args) const - { return operator()(__ref.get(), std::forward<_Args>(__args)...); } + template<typename _Res, typename _Class, typename... _ArgTypes> + 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<typename _Res, typename _Class, typename... _ArgTypes> + 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<typename _Res, typename _Class, typename... _ArgTypes> - 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<typename _Tp, typename... _Args> - _Res - _M_call(_Tp&& __object, const volatile _Class *, - _Args&&... __args) const - { - return (std::forward<_Tp>(__object).*__pmf) - (std::forward<_Args>(__args)...); - } + template<typename _Res, typename _Class, typename... _ArgTypes> + 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<typename _Tp, typename... _Args> - _Res - _M_call(_Tp&& __ptr, const volatile void *, _Args&&... __args) const - { return ((*__ptr).*__pmf)(std::forward<_Args>(__args)...); } + template<typename _Res, typename _Class, typename... _ArgTypes> + 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<typename... _Args> - using _RequireValidArgs - = _Require<_AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; + template<typename _Res, typename _Class, typename... _ArgTypes> + 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<typename _Tp, typename... _Args> - using _RequireValidArgs2 - = _Require<_NotSame<_Class, _Tp>, _NotSame<volatile _Class*, _Tp>, - _AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; + template<typename _Res, typename _Class, typename... _ArgTypes> + 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<typename _Tp, typename... _Args> - using _RequireValidArgs3 - = _Require<is_base_of<_Class, _Tp>, - _AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; + template<typename _MemFunPtr, + bool __is_mem_fn = is_member_function_pointer<_MemFunPtr>::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<typename... _Args, typename _Req = _RequireValidArgs<_Args...>> - _Res - operator()(volatile _Class& __object, _Args&&... __args) const - { return (__object.*__pmf)(std::forward<_Args>(__args)...); } - - template<typename... _Args, typename _Req = _RequireValidArgs<_Args...>> - _Res - operator()(volatile _Class&& __object, _Args&&... __args) const - { - return (std::move(__object).*__pmf)(std::forward<_Args>(__args)...); - } - - // Handle pointers - template<typename... _Args, typename _Req = _RequireValidArgs<_Args...>> - _Res - operator()(volatile _Class* __object, _Args&&... __args) const - { return (__object->*__pmf)(std::forward<_Args>(__args)...); } - - // Handle smart pointers, references and pointers to derived - template<typename _Tp, typename... _Args, - typename _Req = _RequireValidArgs2<_Tp, _Args...>> - _Res - operator()(_Tp&& __object, _Args&&... __args) const - { - return _M_call(std::forward<_Tp>(__object), &__object, - std::forward<_Args>(__args)...); - } - - template<typename _Tp, typename... _Args, - typename _Req = _RequireValidArgs3<_Tp, _Args...>> - _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<typename _Res, typename _Class, typename... _ArgTypes> - 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<typename _Tp, typename... _Args> - _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<typename _Tp, typename... _Args> - _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<typename... _Args> 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<typename _Tp, typename... _Args> using _RequireValidArgs2 - = _Require<_NotSame<_Class, _Tp>, - _NotSame<const volatile _Class*, _Tp>, - _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<typename _Tp, typename... _Args> using _RequireValidArgs3 = _Require<is_base_of<_Class, _Tp>, - _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<typename... _Args, typename _Req = _RequireValidArgs<_Args...>> - _Res - operator()(const volatile _Class& __object, _Args&&... __args) const - { return (__object.*__pmf)(std::forward<_Args>(__args)...); } - - template<typename... _Args, typename _Req = _RequireValidArgs<_Args...>> - _Res - operator()(const volatile _Class&& __object, _Args&&... __args) const + template<typename... _Args, typename _Req + = _Require<typename _Traits::__lvalue, + _AllConvertible<_Pack<_Args...>, _ArgTypes>>> + result_type + operator()(_Class& __object, _Args&&... __args) const + { return (__object.*_M_pmf)(std::forward<_Args>(__args)...); } + + template<typename... _Args, typename _Req + = _Require<typename _Traits::__rvalue, + _AllConvertible<_Pack<_Args...>, _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<typename... _Args, typename _Req = _RequireValidArgs<_Args...>> - _Res - operator()(const volatile _Class* __object, _Args&&... __args) const - { return (__object->*__pmf)(std::forward<_Args>(__args)...); } + template<typename... _Args, typename _Req + = _Require<typename _Traits::__lvalue, + _AllConvertible<_Pack<_Args...>, _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<typename _Tp, typename... _Args, - typename _Req = _RequireValidArgs2<_Tp, _Args...>> - _Res operator()(_Tp&& __object, _Args&&... __args) const + // TODO how to constrain to lvalue/rvalue here? constrain _M_call? + template<typename _Tp, typename... _Args, typename _Req + = _Require<_NotSame<_Class, _Tp>, _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<typename _Tp, typename... _Args, - typename _Req = _RequireValidArgs3<_Tp, _Args...>> - _Res + // Handle reference wrappers + template<typename _Tp, typename... _Args, typename _Req + = _Require<is_base_of<_Class, _Tp>, + 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<typename _Tp, bool> - struct _Mem_fn_const_or_non - { - typedef const _Tp& type; - }; - - template<typename _Tp> - struct _Mem_fn_const_or_non<_Tp, false> - { - typedef _Tp& type; + _Pmf _M_pmf; }; + // Partial specialization for member object pointers. template<typename _Res, typename _Class> - 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<typename _Tp, typename _Up> 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<typename _Tp> 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<const _Class>(__object).*__pm; } + { return std::forward<const _Class>(__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<typename _Tp, typename _Req = _Require<_NotSame<_Class*, _Tp>>> 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<typename _Tp, typename _Req = _Require<is_base_of<_Class, _Tp>>> 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<typename _Res, typename _Class> + 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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++11" } +// { dg-do compile } + +#include <functional> + +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) ); +}
commit 9e8b41f93b5d3e6f9578fbfe9bccd7ae691733ea Author: Jonathan Wakely <jwak...@redhat.com> 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<size_t, sizeof...(_ArgTypes)>; }; template<typename _Res, typename _Class, typename... _ArgTypes> @@ -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<size_t, 0>; + 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<const volatile _Bind_result<_Result, _Signature>> : public true_type { }; + template<typename _Func, typename... _BoundArgs> + struct _Bind_check_arity { }; + + template<typename _Ret, typename... _Args, typename... _BoundArgs> + struct _Bind_check_arity<_Ret (*)(_Args...), _BoundArgs...> + { + static_assert(sizeof...(_BoundArgs) == sizeof...(_Args), + "Wrong number of arguments for function"); + }; + + template<typename _Tp, typename _Class, typename... _BoundArgs> + 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<bool _SocketLike, typename _Func, typename... _BoundArgs> struct _Bind_helper + : _Bind_check_arity<typename decay<_Func>::type, _BoundArgs...> { typedef _Maybe_wrap_member_pointer<typename decay<_Func>::type> __maybe_type; @@ -1525,6 +1548,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) template<typename _Result, typename _Func, typename... _BoundArgs> struct _Bindres_helper + : _Bind_check_arity<typename decay<_Func>::type, _BoundArgs...> { typedef _Maybe_wrap_member_pointer<typename decay<_Func>::type> __maybe_type; @@ -1599,6 +1623,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) template<typename _Func, typename... _BoundArgs> struct _Bind_simple_helper + : _Bind_check_arity<typename decay<_Func>::type, _BoundArgs...> { typedef _Maybe_wrap_member_pointer<typename decay<_Func>::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" } }