Commit f6b640be by Jonathan Wakely Committed by Jonathan Wakely

Make std::mem_fn work with varargs functions.

	* include/std/functional (_Mem_fn_traits): Add partial specializations
	for varargs functions.
	(_Mem_fn_base): Do not check arguments are convertible for varargs.
	(_Bind_check_arity): Add partial specializations for varargs functions.
	* include/std/type_traits (__bool_constant): Add alias template.
	* testsuite/20_util/bind/ref_neg.cc: Adjust dg-error.
	* testsuite/20_util/bind/refqual.cc: New, test ref-qualifiers.
	* testsuite/20_util/declval/requirements/1_neg.cc: Adjust dg-error.
	* testsuite/20_util/function_objects/mem_fn/refqual.cc: Test varargs.
	* testsuite/20_util/make_signed/requirements/typedefs_neg.cc: Adjust
	dg-error.
	* testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc: Adjust
	dg-error.

From-SVN: r217393
parent 3d00119c
2014-11-11 Jonathan Wakely <jwakely@redhat.com>
* include/std/functional (_Mem_fn_traits): Add partial specializations
for varargs functions.
(_Mem_fn_base): Do not check arguments are convertible for varargs.
(_Bind_check_arity): Add partial specializations for varargs functions.
* include/std/type_traits (__bool_constant): Add alias template.
* testsuite/20_util/bind/ref_neg.cc: Adjust dg-error.
* testsuite/20_util/bind/refqual.cc: New, test ref-qualifiers.
* testsuite/20_util/declval/requirements/1_neg.cc: Adjust dg-error.
* testsuite/20_util/function_objects/mem_fn/refqual.cc: Test varargs.
* testsuite/20_util/make_signed/requirements/typedefs_neg.cc: Adjust
dg-error.
* testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc: Adjust
dg-error.
2014-11-11 Siva Chandra Reddy <sivachandra@google.com> 2014-11-11 Siva Chandra Reddy <sivachandra@google.com>
* testsuite/libstdc++-xmethods/associative-containers.cc: Add new * testsuite/libstdc++-xmethods/associative-containers.cc: Add new
......
...@@ -512,113 +512,38 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) ...@@ -512,113 +512,38 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type)
using __arity = integral_constant<size_t, sizeof...(_ArgTypes)>; using __arity = integral_constant<size_t, sizeof...(_ArgTypes)>;
}; };
template<typename _Res, typename _Class, typename... _ArgTypes> #define _GLIBCXX_MEM_FN_TRAITS2(_CV, _REF, _LVAL, _RVAL) \
struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...)> template<typename _Res, typename _Class, typename... _ArgTypes> \
: _Mem_fn_traits_base<_Res, _Class, _ArgTypes...> struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) _CV _REF> \
{ : _Mem_fn_traits_base<_Res, _CV _Class, _ArgTypes...> \
using __pmf_type = _Res (_Class::*)(_ArgTypes...); { \
using __lvalue = true_type; using __pmf_type = _Res (_Class::*)(_ArgTypes...) _CV _REF; \
using __rvalue = true_type; using __lvalue = _LVAL; \
}; using __rvalue = _RVAL; \
using __vararg = false_type; \
template<typename _Res, typename _Class, typename... _ArgTypes> }; \
struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) const> template<typename _Res, typename _Class, typename... _ArgTypes> \
: _Mem_fn_traits_base<_Res, const _Class, _ArgTypes...> struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes... ...) _CV _REF> \
{ : _Mem_fn_traits_base<_Res, _CV _Class, _ArgTypes...> \
using __pmf_type = _Res (_Class::*)(_ArgTypes...) const; { \
using __lvalue = true_type; using __pmf_type = _Res (_Class::*)(_ArgTypes... ...) _CV _REF; \
using __rvalue = true_type; using __lvalue = _LVAL; \
using __rvalue = _RVAL; \
using __vararg = true_type; \
}; };
template<typename _Res, typename _Class, typename... _ArgTypes> #define _GLIBCXX_MEM_FN_TRAITS(_REF, _LVAL, _RVAL) \
struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) volatile> _GLIBCXX_MEM_FN_TRAITS2( , _REF, _LVAL, _RVAL) \
: _Mem_fn_traits_base<_Res, volatile _Class, _ArgTypes...> _GLIBCXX_MEM_FN_TRAITS2(const , _REF, _LVAL, _RVAL) \
{ _GLIBCXX_MEM_FN_TRAITS2(volatile , _REF, _LVAL, _RVAL) \
using __pmf_type = _Res (_Class::*)(_ArgTypes...) volatile; _GLIBCXX_MEM_FN_TRAITS2(const volatile, _REF, _LVAL, _RVAL)
using __lvalue = true_type;
using __rvalue = true_type;
};
template<typename _Res, typename _Class, typename... _ArgTypes> _GLIBCXX_MEM_FN_TRAITS( , true_type, true_type)
struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) const volatile> _GLIBCXX_MEM_FN_TRAITS(&, true_type, false_type)
: _Mem_fn_traits_base<_Res, const volatile _Class, _ArgTypes...> _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
{
using __pmf_type = _Res (_Class::*)(_ArgTypes...) const volatile;
using __lvalue = true_type;
using __rvalue = true_type;
};
template<typename _Res, typename _Class, typename... _ArgTypes> #undef _GLIBCXX_MEM_FN_TRAITS
struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...)&> #undef _GLIBCXX_MEM_FN_TRAITS2
: _Mem_fn_traits_base<_Res, _Class, _ArgTypes...>
{
using __pmf_type = _Res (_Class::*)(_ArgTypes...)&;
using __lvalue = true_type;
using __rvalue = false_type;
};
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;
};
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;
};
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 = false_type;
};
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 _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 _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 _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 _MemFunPtr, template<typename _MemFunPtr,
bool __is_mem_fn = is_member_function_pointer<_MemFunPtr>::value> bool __is_mem_fn = is_member_function_pointer<_MemFunPtr>::value>
...@@ -627,62 +552,40 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) ...@@ -627,62 +552,40 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type)
{ {
using _Traits = _Mem_fn_traits<_MemFunPtr>; using _Traits = _Mem_fn_traits<_MemFunPtr>;
public:
using result_type = typename _Traits::__result_type;
using _Arity = typename _Traits::__arity;
private:
using _Class = typename _Traits::__class_type; using _Class = typename _Traits::__class_type;
using _ArgTypes = typename _Traits::__arg_types; using _ArgTypes = typename _Traits::__arg_types;
using _Pmf = typename _Traits::__pmf_type; using _Pmf = typename _Traits::__pmf_type;
template<typename _Tp, typename... _Args> using _Arity = typename _Traits::__arity;
result_type using _Varargs = typename _Traits::__vararg;
_M_call(_Tp&& __object, const volatile _Class *,
_Args&&... __args) const
{
return (std::forward<_Tp>(__object).*_M_pmf)
(std::forward<_Args>(__args)...);
}
template<typename _Tp, typename... _Args>
result_type
_M_call(_Tp&& __ptr, const volatile void *, _Args&&... __args) const
{ 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...>, _ArgTypes>>;
// Require each _Args to be convertible to corresponding _ArgTypes template<typename _Func, typename... _BoundArgs>
// and require _Tp is not _Class, _Class& or _Class* friend struct _Bind_check_arity;
template<typename _Tp, typename... _Args>
using _RequireValidArgs2
= _Require<_NotSame<_Class, _Tp>, _NotSame<_Class*, _Tp>,
_AllConvertible<_Pack<_Args...>, _ArgTypes>>;
// Require each _Args to be convertible to corresponding _ArgTypes // for varargs functions we just check the number of arguments,
// and require _Tp is _Class or derived from _Class // otherwise we also check they are convertible.
template<typename _Tp, typename... _Args> template<typename _Args>
using _RequireValidArgs3 using _CheckArgs = typename conditional<_Varargs::value,
= _Require<is_base_of<_Class, _Tp>, __bool_constant<(_Args::value >= _ArgTypes::value)>,
_AllConvertible<_Pack<_Args...>, _ArgTypes>>; _AllConvertible<_Args, _ArgTypes>
>::type;
public: public:
using result_type = typename _Traits::__result_type;
explicit _Mem_fn_base(_Pmf __pmf) : _M_pmf(__pmf) { } explicit _Mem_fn_base(_Pmf __pmf) : _M_pmf(__pmf) { }
// Handle objects // Handle objects
template<typename... _Args, typename _Req template<typename... _Args, typename _Req
= _Require<typename _Traits::__lvalue, = _Require<typename _Traits::__lvalue,
_AllConvertible<_Pack<_Args...>, _ArgTypes>>> _CheckArgs<_Pack<_Args...>>>>
result_type result_type
operator()(_Class& __object, _Args&&... __args) const operator()(_Class& __object, _Args&&... __args) const
{ return (__object.*_M_pmf)(std::forward<_Args>(__args)...); } { return (__object.*_M_pmf)(std::forward<_Args>(__args)...); }
template<typename... _Args, typename _Req template<typename... _Args, typename _Req
= _Require<typename _Traits::__rvalue, = _Require<typename _Traits::__rvalue,
_AllConvertible<_Pack<_Args...>, _ArgTypes>>> _CheckArgs<_Pack<_Args...>>>>
result_type result_type
operator()(_Class&& __object, _Args&&... __args) const operator()(_Class&& __object, _Args&&... __args) const
{ {
...@@ -692,16 +595,15 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) ...@@ -692,16 +595,15 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type)
// Handle pointers // Handle pointers
template<typename... _Args, typename _Req template<typename... _Args, typename _Req
= _Require<typename _Traits::__lvalue, = _Require<typename _Traits::__lvalue,
_AllConvertible<_Pack<_Args...>, _ArgTypes>>> _CheckArgs<_Pack<_Args...>>>>
result_type result_type
operator()(_Class* __object, _Args&&... __args) const operator()(_Class* __object, _Args&&... __args) const
{ return (__object->*_M_pmf)(std::forward<_Args>(__args)...); } { return (__object->*_M_pmf)(std::forward<_Args>(__args)...); }
// Handle smart pointers, references and pointers to derived // Handle smart pointers, references and pointers to derived
// TODO how to constrain to lvalue/rvalue here? constrain _M_call?
template<typename _Tp, typename... _Args, typename _Req template<typename _Tp, typename... _Args, typename _Req
= _Require<_NotSame<_Class, _Tp>, _NotSame<_Class*, _Tp>, = _Require<_NotSame<_Class, _Tp>, _NotSame<_Class*, _Tp>,
_AllConvertible<_Pack<_Args...>, _ArgTypes>>> _CheckArgs<_Pack<_Args...>>>>
result_type result_type
operator()(_Tp&& __object, _Args&&... __args) const operator()(_Tp&& __object, _Args&&... __args) const
{ {
...@@ -711,14 +613,27 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) ...@@ -711,14 +613,27 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type)
// Handle reference wrappers // Handle reference wrappers
template<typename _Tp, typename... _Args, typename _Req template<typename _Tp, typename... _Args, typename _Req
= _Require<is_base_of<_Class, _Tp>, = _Require<is_base_of<_Class, _Tp>, typename _Traits::__lvalue,
typename _Traits::__lvalue, _CheckArgs<_Pack<_Args...>>>>
_AllConvertible<_Pack<_Args...>, _ArgTypes>>>
result_type result_type
operator()(reference_wrapper<_Tp> __ref, _Args&&... __args) const operator()(reference_wrapper<_Tp> __ref, _Args&&... __args) const
{ return operator()(__ref.get(), std::forward<_Args>(__args)...); } { return operator()(__ref.get(), std::forward<_Args>(__args)...); }
private: private:
template<typename _Tp, typename... _Args>
result_type
_M_call(_Tp&& __object, const volatile _Class *,
_Args&&... __args) const
{
return (std::forward<_Tp>(__object).*_M_pmf)
(std::forward<_Args>(__args)...);
}
template<typename _Tp, typename... _Args>
result_type
_M_call(_Tp&& __ptr, const volatile void *, _Args&&... __args) const
{ return ((*__ptr).*_M_pmf)(std::forward<_Args>(__args)...); }
_Pmf _M_pmf; _Pmf _M_pmf;
}; };
...@@ -750,9 +665,13 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) ...@@ -750,9 +665,13 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type)
-> decltype((*__ptr).*std::declval<__pm_type&>()) -> decltype((*__ptr).*std::declval<__pm_type&>())
{ return (*__ptr).*_M_pm; } { return (*__ptr).*_M_pm; }
public:
using _Arity = integral_constant<size_t, 0>; using _Arity = integral_constant<size_t, 0>;
using _Varargs = false_type;
template<typename _Func, typename... _BoundArgs>
friend struct _Bind_check_arity;
public:
explicit explicit
_Mem_fn_base(_Res _Class::*__pm) noexcept : _M_pm(__pm) { } _Mem_fn_base(_Res _Class::*__pm) noexcept : _M_pm(__pm) { }
...@@ -1493,12 +1412,22 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) ...@@ -1493,12 +1412,22 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type)
"Wrong number of arguments for function"); "Wrong number of arguments for function");
}; };
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> template<typename _Tp, typename _Class, typename... _BoundArgs>
struct _Bind_check_arity<_Tp _Class::*, _BoundArgs...> struct _Bind_check_arity<_Tp _Class::*, _BoundArgs...>
{ {
using _Arity = typename _Mem_fn<_Tp _Class::*>::_Arity; using _Arity = typename _Mem_fn<_Tp _Class::*>::_Arity;
static_assert(sizeof...(_BoundArgs) == _Arity::value + 1, using _Varargs = typename _Mem_fn<_Tp _Class::*>::_Varargs;
"Wrong number of arguments for pointer-to-member"); static_assert(_Varargs::value
? sizeof...(_BoundArgs) >= _Arity::value + 1
: 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 // Trait type used to remove std::bind() from overload set via SFINAE
......
...@@ -89,6 +89,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -89,6 +89,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// The type used as a compile-time boolean with false value. /// The type used as a compile-time boolean with false value.
typedef integral_constant<bool, false> false_type; typedef integral_constant<bool, false> false_type;
template<bool __v>
using __bool_constant = integral_constant<bool, __v>;
// Meta programming helper types. // Meta programming helper types.
template<bool, typename, typename> template<bool, typename, typename>
......
...@@ -30,10 +30,10 @@ void test01() ...@@ -30,10 +30,10 @@ void test01()
{ {
const int dummy = 0; const int dummy = 0;
std::bind(&inc, _1)(0); // { dg-error "no match" } std::bind(&inc, _1)(0); // { dg-error "no match" }
// { dg-error "rvalue|const" "" { target *-*-* } 1207 } // { dg-error "rvalue|const" "" { target *-*-* } 1126 }
// { dg-error "rvalue|const" "" { target *-*-* } 1221 } // { dg-error "rvalue|const" "" { target *-*-* } 1140 }
// { dg-error "rvalue|const" "" { target *-*-* } 1235 } // { dg-error "rvalue|const" "" { target *-*-* } 1154 }
// { dg-error "rvalue|const" "" { target *-*-* } 1249 } // { dg-error "rvalue|const" "" { target *-*-* } 1168 }
std::bind(&inc, std::ref(dummy))(); // { dg-error "no match" } std::bind(&inc, std::ref(dummy))(); // { dg-error "no match" }
} }
......
// 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" }
#include <functional>
#include <testsuite_hooks.h>
struct X
{
int f() const& { return 0; }
int g(int i, ...)& { return i; }
};
void
test01()
{
X x;
auto b = std::bind(&X::f, &x);
VERIFY( b() == 0 );
auto bb = std::bind(&X::g, &x, 1, 2);
VERIFY( bb() == 1 );
}
int
main()
{
test01();
}
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
// with this library; see the file COPYING3. If not see // with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>. // <http://www.gnu.org/licenses/>.
// { dg-error "static assertion failed" "" { target *-*-* } 2201 } // { dg-error "static assertion failed" "" { target *-*-* } 2204 }
#include <utility> #include <utility>
......
...@@ -24,6 +24,7 @@ struct Foo ...@@ -24,6 +24,7 @@ struct Foo
{ {
void r()&& { } void r()&& { }
int l() const& { return 0; } int l() const& { return 0; }
void lv(int, ...)& { }
}; };
void test01() void test01()
...@@ -31,4 +32,5 @@ void test01() ...@@ -31,4 +32,5 @@ void test01()
Foo f; Foo f;
int i = std::mem_fn(&Foo::l)( f ); int i = std::mem_fn(&Foo::l)( f );
std::mem_fn(&Foo::r)( std::move(f) ); std::mem_fn(&Foo::r)( std::move(f) );
std::mem_fn(&Foo::lv)( f, 1, 2, 3 );
} }
...@@ -48,5 +48,5 @@ void test01() ...@@ -48,5 +48,5 @@ void test01()
// { dg-error "required from here" "" { target *-*-* } 40 } // { dg-error "required from here" "" { target *-*-* } 40 }
// { dg-error "required from here" "" { target *-*-* } 42 } // { dg-error "required from here" "" { target *-*-* } 42 }
// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1866 } // { dg-error "invalid use of incomplete type" "" { target *-*-* } 1869 }
// { dg-error "declaration of" "" { target *-*-* } 1830 } // { dg-error "declaration of" "" { target *-*-* } 1833 }
...@@ -48,5 +48,5 @@ void test01() ...@@ -48,5 +48,5 @@ void test01()
// { dg-error "required from here" "" { target *-*-* } 40 } // { dg-error "required from here" "" { target *-*-* } 40 }
// { dg-error "required from here" "" { target *-*-* } 42 } // { dg-error "required from here" "" { target *-*-* } 42 }
// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1754 } // { dg-error "invalid use of incomplete type" "" { target *-*-* } 1757 }
// { dg-error "declaration of" "" { target *-*-* } 1718 } // { dg-error "declaration of" "" { target *-*-* } 1721 }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment