From b1c2b51b6662adebbc37c6590d697e9fe3439076 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Wed, 28 Nov 2012 01:42:25 +0000 Subject: [PATCH] functional (_Mem_fn): Constrain function call operators to avoid ambiguities. * include/std/functional (_Mem_fn): Constrain function call operators to avoid ambiguities. Use perfect forwarding. * testsuite/20_util/function_objects/mem_fn/55463.cc: Additional tests. * testsuite/20_util/function_objects/mem_fn/forward.cc: New. * testsuite/20_util/bind/ref_neg.cc: Adjust dg-error line numbers. From-SVN: r193879 --- libstdc++-v3/ChangeLog | 9 + libstdc++-v3/include/std/functional | 277 +++++++++++++++------ libstdc++-v3/testsuite/20_util/bind/ref_neg.cc | 8 +- .../20_util/function_objects/mem_fn/55463.cc | 42 +++- .../20_util/function_objects/mem_fn/forward.cc | 62 +++++ 5 files changed, 312 insertions(+), 86 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/function_objects/mem_fn/forward.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 9d22b9d..ac1e7cb 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,12 @@ +2012-11-28 Jonathan Wakely + + * include/std/functional (_Mem_fn): Constrain function call operators + to avoid ambiguities. Use perfect forwarding. + * testsuite/20_util/function_objects/mem_fn/55463.cc: Additional + tests. + * testsuite/20_util/function_objects/mem_fn/forward.cc: New. + * testsuite/20_util/bind/ref_neg.cc: Adjust dg-error line numbers. + 2012-11-27 Ollie Wild * include/bits/stl_tree.h (@headername): Fix incorrect Doxygen macro diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index 0d8fbd6..604481b 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -501,6 +501,26 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) // @} group functors + template + using _Require = typename enable_if<__and_<_Cond...>::value>::type; + + template + struct _Pack : integral_constant + { }; + + template + struct _AllConvertible : false_type + { }; + + template + struct _AllConvertible<_Pack<_From...>, _Pack<_To...>, true> + : __and_...> + { }; + + template + using _NotSame = __not_::type, + typename std::decay<_Tp2>::type>>; + /** * Derives from @c unary_function or @c binary_function, or perhaps * nothing, depending on the number of arguments provided. The @@ -526,19 +546,38 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) { typedef _Res (_Class::*_Functor)(_ArgTypes...); - template + template _Res _M_call(_Tp&& __object, const volatile _Class *, - _ArgTypes... __args) const + _Args&&... __args) const { return (std::forward<_Tp>(__object).*__pmf) - (std::forward<_ArgTypes>(__args)...); + (std::forward<_Args>(__args)...); } - template + template _Res - _M_call(_Tp&& __ptr, const volatile void *, _ArgTypes... __args) const - { return ((*__ptr).*__pmf)(std::forward<_ArgTypes>(__args)...); } + _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; @@ -546,28 +585,39 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) explicit _Mem_fn(_Functor __pmf) : __pmf(__pmf) { } // Handle objects - _Res - operator()(_Class& __object, _ArgTypes... __args) const - { return (__object.*__pmf)(std::forward<_ArgTypes>(__args)...); } + 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 - _Res - operator()(_Class* __object, _ArgTypes... __args) const - { return (__object->*__pmf)(std::forward<_ArgTypes>(__args)...); } + template> + _Res + operator()(_Class* __object, _Args&&... __args) const + { return (__object->*__pmf)(std::forward<_Args>(__args)...); } // Handle smart pointers, references and pointers to derived - template + template> _Res - operator()(_Tp&& __object, _ArgTypes... __args) const + operator()(_Tp&& __object, _Args&&... __args) const { return _M_call(std::forward<_Tp>(__object), &__object, - std::forward<_ArgTypes>(__args)...); + std::forward<_Args>(__args)...); } - template + template> _Res - operator()(reference_wrapper<_Tp> __ref, _ArgTypes... __args) const - { return operator()(__ref.get(), std::forward<_ArgTypes>(__args)...); } + operator()(reference_wrapper<_Tp> __ref, _Args&&... __args) const + { return operator()(__ref.get(), std::forward<_Args>(__args)...); } private: _Functor __pmf; @@ -581,19 +631,33 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) { typedef _Res (_Class::*_Functor)(_ArgTypes...) const; - template + template _Res _M_call(_Tp&& __object, const volatile _Class *, - _ArgTypes... __args) const + _Args&&... __args) const { return (std::forward<_Tp>(__object).*__pmf) - (std::forward<_ArgTypes>(__args)...); + (std::forward<_Args>(__args)...); } - template + template _Res - _M_call(_Tp&& __ptr, const volatile void *, _ArgTypes... __args) const - { return ((*__ptr).*__pmf)(std::forward<_ArgTypes>(__args)...); } + _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<_Class*, _Tp>, + _AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; + + template + using _RequireValidArgs3 + = _Require, + _AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; public: typedef _Res result_type; @@ -601,27 +665,38 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) explicit _Mem_fn(_Functor __pmf) : __pmf(__pmf) { } // Handle objects - _Res - operator()(const _Class& __object, _ArgTypes... __args) const - { return (__object.*__pmf)(std::forward<_ArgTypes>(__args)...); } + 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)...); + } // Handle pointers - _Res - operator()(const _Class* __object, _ArgTypes... __args) const - { return (__object->*__pmf)(std::forward<_ArgTypes>(__args)...); } + template> + _Res + operator()(const _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, _ArgTypes... __args) const + template> + _Res operator()(_Tp&& __object, _Args&&... __args) const { return _M_call(std::forward<_Tp>(__object), &__object, - std::forward<_ArgTypes>(__args)...); + std::forward<_Args>(__args)...); } - template + template> _Res - operator()(reference_wrapper<_Tp> __ref, _ArgTypes... __args) const - { return operator()(__ref.get(), std::forward<_ArgTypes>(__args)...); } + operator()(reference_wrapper<_Tp> __ref, _Args&&... __args) const + { return operator()(__ref.get(), std::forward<_Args>(__args)...); } private: _Functor __pmf; @@ -635,19 +710,33 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) { typedef _Res (_Class::*_Functor)(_ArgTypes...) volatile; - template + template _Res _M_call(_Tp&& __object, const volatile _Class *, - _ArgTypes... __args) const + _Args&&... __args) const { return (std::forward<_Tp>(__object).*__pmf) - (std::forward<_ArgTypes>(__args)...); + (std::forward<_Args>(__args)...); } - template + template _Res - _M_call(_Tp&& __ptr, const volatile void *, _ArgTypes... __args) const - { return ((*__ptr).*__pmf)(std::forward<_ArgTypes>(__args)...); } + _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<_Class*, _Tp>, + _AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; + + template + using _RequireValidArgs3 + = _Require, + _AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; public: typedef _Res result_type; @@ -655,28 +744,39 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) explicit _Mem_fn(_Functor __pmf) : __pmf(__pmf) { } // Handle objects - _Res - operator()(volatile _Class& __object, _ArgTypes... __args) const - { return (__object.*__pmf)(std::forward<_ArgTypes>(__args)...); } + 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 - _Res - operator()(volatile _Class* __object, _ArgTypes... __args) const - { return (__object->*__pmf)(std::forward<_ArgTypes>(__args)...); } + 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 + template> _Res - operator()(_Tp&& __object, _ArgTypes... __args) const + operator()(_Tp&& __object, _Args&&... __args) const { return _M_call(std::forward<_Tp>(__object), &__object, - std::forward<_ArgTypes>(__args)...); + std::forward<_Args>(__args)...); } - template + template> _Res - operator()(reference_wrapper<_Tp> __ref, _ArgTypes... __args) const - { return operator()(__ref.get(), std::forward<_ArgTypes>(__args)...); } + operator()(reference_wrapper<_Tp> __ref, _Args&&... __args) const + { return operator()(__ref.get(), std::forward<_Args>(__args)...); } private: _Functor __pmf; @@ -690,19 +790,33 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) { typedef _Res (_Class::*_Functor)(_ArgTypes...) const volatile; - template + template _Res _M_call(_Tp&& __object, const volatile _Class *, - _ArgTypes... __args) const + _Args&&... __args) const { return (std::forward<_Tp>(__object).*__pmf) - (std::forward<_ArgTypes>(__args)...); + (std::forward<_Args>(__args)...); } - template + template _Res - _M_call(_Tp&& __ptr, const volatile void *, _ArgTypes... __args) const - { return ((*__ptr).*__pmf)(std::forward<_ArgTypes>(__args)...); } + _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<_Class*, _Tp>, + _AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; + + template + using _RequireValidArgs3 + = _Require, + _AllConvertible<_Pack<_Args...>, _Pack<_ArgTypes...>>>; public: typedef _Res result_type; @@ -710,27 +824,38 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) explicit _Mem_fn(_Functor __pmf) : __pmf(__pmf) { } // Handle objects - _Res - operator()(const volatile _Class& __object, _ArgTypes... __args) const - { return (__object.*__pmf)(std::forward<_ArgTypes>(__args)...); } + 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 + { + return (std::move(__object).*__pmf)(std::forward<_Args>(__args)...); + } // Handle pointers - _Res - operator()(const volatile _Class* __object, _ArgTypes... __args) const - { return (__object->*__pmf)(std::forward<_ArgTypes>(__args)...); } + template> + _Res + operator()(const 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, _ArgTypes... __args) const + template> + _Res operator()(_Tp&& __object, _Args&&... __args) const { return _M_call(std::forward<_Tp>(__object), &__object, - std::forward<_ArgTypes>(__args)...); + std::forward<_Args>(__args)...); } - template + template> _Res - operator()(reference_wrapper<_Tp> __ref, _ArgTypes... __args) const - { return operator()(__ref.get(), std::forward<_ArgTypes>(__args)...); } + operator()(reference_wrapper<_Tp> __ref, _Args&&... __args) const + { return operator()(__ref.get(), std::forward<_Args>(__args)...); } private: _Functor __pmf; @@ -756,7 +881,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) // This bit of genius is due to Peter Dimov, improved slightly by // Douglas Gregor. - // Made less elegant by Jonathan Wakely to support perfect forwarding. + // Made less elegant to support perfect forwarding and noexcept. template auto _M_call(_Tp&& __object, const _Class *) const noexcept @@ -807,7 +932,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) { return __object->*__pm; } // Handle smart pointers and derived - template + template>> auto operator()(_Tp&& __unknown) const noexcept(noexcept(std::declval<_Mem_fn*>()->_M_call @@ -815,12 +940,12 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) -> 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&>()(__ref.get()))) -> decltype((*this)(__ref.get())) - { return operator()(__ref.get()); } + { return (*this)(__ref.get()); } private: _Res _Class::*__pm; diff --git a/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc b/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc index c7f605e..bae0a86 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 *-*-* } 1224 } - // { dg-error "rvalue|const" "" { target *-*-* } 1238 } - // { dg-error "rvalue|const" "" { target *-*-* } 1252 } - // { dg-error "rvalue|const" "" { target *-*-* } 1266 } + // { dg-error "rvalue|const" "" { target *-*-* } 1349 } + // { dg-error "rvalue|const" "" { target *-*-* } 1363 } + // { dg-error "rvalue|const" "" { target *-*-* } 1377 } + // { dg-error "rvalue|const" "" { target *-*-* } 1391 } std::bind(&inc, std::ref(dummy))(); // { dg-error "no match" } } 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 5adce1b..ac11852 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 @@ -32,7 +32,12 @@ struct X int data; }; +struct Y : X { }; + using CX = const X; +using CY = const Y; + +using X_ptr = X*; struct smart_ptr { @@ -41,38 +46,63 @@ struct smart_ptr std::reference_wrapper ref(); std::reference_wrapper cref(); +std::reference_wrapper yref(); void test01() { int& i1 = std::mem_fn( &X::func )( X() ); - int& i2 = std::mem_fn( &X::func )( smart_ptr() ); + int& i2 = std::mem_fn( &X::func )( Y() ); int& i3 = std::mem_fn( &X::func )( ref() ); + int& i4 = std::mem_fn( &X::func )( yref() ); + int& i5 = std::mem_fn( &X::func )( X_ptr() ); + int& i6 = std::mem_fn( &X::func )( smart_ptr() ); char& c1 = std::mem_fn( &X::func_c )( X() ); char& c2 = std::mem_fn( &X::func_c )( CX() ); - char& c3 = std::mem_fn( &X::func_c )( smart_ptr() ); + char& c3 = std::mem_fn( &X::func_c )( Y() ); char& c4 = std::mem_fn( &X::func_c )( ref() ); char& c5 = std::mem_fn( &X::func_c )( cref() ); + char& c6 = std::mem_fn( &X::func_c )( yref() ); + char& c7 = std::mem_fn( &X::func_c )( X_ptr() ); + char& c8 = std::mem_fn( &X::func_c )( smart_ptr() ); short& s1 = std::mem_fn( &X::func_v )( X() ); - short& s2 = std::mem_fn( &X::func_v )( smart_ptr() ); + short& s2 = std::mem_fn( &X::func_v )( Y() ); short& s3 = std::mem_fn( &X::func_v )( ref() ); + short& s4 = std::mem_fn( &X::func_v )( yref() ); + short& s5 = std::mem_fn( &X::func_v )( X_ptr() ); + short& s6 = std::mem_fn( &X::func_v )( smart_ptr() ); double& d1 = std::mem_fn( &X::func_cv )( X() ); double& d2 = std::mem_fn( &X::func_cv )( CX() ); - double& d3 = std::mem_fn( &X::func_cv )( smart_ptr() ); + double& d3 = std::mem_fn( &X::func_cv )( Y() ); double& d4 = std::mem_fn( &X::func_cv )( ref() ); double& d5 = std::mem_fn( &X::func_cv )( cref() ); + double& d6 = std::mem_fn( &X::func_cv )( yref() ); + double& d7 = std::mem_fn( &X::func_cv )( X_ptr() ); + double& d8 = std::mem_fn( &X::func_cv )( smart_ptr() ); // [expr.mptr.oper] // The result of a .* expression whose second operand is a pointer to a // data member is of the same value category (3.10) as its first operand. int&& rval = std::mem_fn( &X::data )( X() ); const int&& crval = std::mem_fn( &X::data )( CX() ); - - int& sval = std::mem_fn( &X::data )( smart_ptr() ); + int&& yrval = std::mem_fn( &X::data )( Y() ); + const int&& ycrval = std::mem_fn( &X::data )( CY() ); int& val = std::mem_fn( &X::data )( ref() ); const int& cval = std::mem_fn( &X::data )( cref() ); + int& yval = std::mem_fn( &X::data )( yref() ); + + int& pval = std::mem_fn( &X::data )( X_ptr() ); + int& sval = std::mem_fn( &X::data )( smart_ptr() ); } +void test02() +{ + std::reference_wrapper r = ref(); + X& x1 = std::mem_fn( &std::reference_wrapper::get )( r ); + const std::reference_wrapper cr = ref(); + const X& x3 = std::mem_fn( &std::reference_wrapper::get )( cr ); + X& x2 = std::mem_fn( &std::reference_wrapper::get )( ref() ); +} diff --git a/libstdc++-v3/testsuite/20_util/function_objects/mem_fn/forward.cc b/libstdc++-v3/testsuite/20_util/function_objects/mem_fn/forward.cc new file mode 100644 index 0000000..a231bf6 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/function_objects/mem_fn/forward.cc @@ -0,0 +1,62 @@ +// { dg-options "-std=gnu++11" } + +// Copyright (C) 2012 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 +// . + +#include +#include + +struct Counter +{ + Counter() = default; + Counter(const Counter&) { ++count; } + + static int count; +}; + +int Counter::count = 0; + +struct X +{ + int func(Counter, int i) { return i; } + char func_c(Counter, char c) const { return c; } + short func_v(Counter, short s) volatile { return s; } + double func_cv(Counter, double d) const volatile { return d; } +}; + +void test01() +{ + Counter c; + X x; + + std::mem_fn( &X::func )( x, c, 0 ); + VERIFY( Counter::count == 1 ); + + std::mem_fn( &X::func_c )( x, c, 0 ); + VERIFY( Counter::count == 2 ); + + std::mem_fn( &X::func_v )( x, c, 0 ); + VERIFY( Counter::count == 3 ); + + std::mem_fn( &X::func_cv )( x, c, 0 ); + VERIFY( Counter::count == 4 ); +} + +int main() +{ + test01(); +} -- 2.7.4