This allows std::bind and tr1::bind to work together and support each other's placeholders and recognise each other's call wrappers as bind expressions.
* include/std/functional (is_placeholder, is_bind_expression): Add partial specializations for cv-qualified types. * include/tr1/functional (is_placeholder, is_bind_expression): Add partial specializations for std::bind and std::placeholders and for cv-qualified types. * testsuite/20_util/bind/cv_quals_3.cc: New. * testsuite/tr1/3_function_objects/bind/cv_quals.cc: New. * testsuite/tr1/3_function_objects/bind/mixed.cc: New. Tested x86_64-linux, committed to trunk.
Index: include/std/functional =================================================================== --- include/std/functional (revision 181606) +++ include/std/functional (revision 181607) @@ -843,22 +843,24 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) : public integral_constant<int, 0> { }; - /// The type of placeholder objects defined by libstdc++. + /** @brief The type of placeholder objects defined by libstdc++. + * @ingroup binders + */ template<int _Num> struct _Placeholder { }; _GLIBCXX_END_NAMESPACE_VERSION /** @namespace std::placeholders - * @brief ISO C++ 0x entities sub namespace for functional. + * @brief ISO C++11 entities sub-namespace for functional. * @ingroup binders - * - * Define a large number of placeholders. There is no way to - * simplify this with variadic templates, because we're introducing - * unique names for each. */ namespace placeholders { _GLIBCXX_BEGIN_NAMESPACE_VERSION + /* Define a large number of placeholders. There is no way to + * simplify this with variadic templates, because we're introducing + * unique names for each. + */ extern const _Placeholder<1> _1; extern const _Placeholder<2> _2; extern const _Placeholder<3> _3; @@ -903,6 +905,11 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) : public integral_constant<int, _Num> { }; + template<int _Num> + struct is_placeholder<const _Placeholder<_Num> > + : public integral_constant<int, _Num> + { }; + /** * Used by _Safe_tuple_element to indicate that there is no tuple * element at this position. @@ -1424,8 +1431,56 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) * @brief Class template _Bind is always a bind expression. * @ingroup binders */ + template<typename _Signature> + struct is_bind_expression<const _Bind<_Signature> > + : public true_type { }; + + /** + * @brief Class template _Bind is always a bind expression. + * @ingroup binders + */ + template<typename _Signature> + struct is_bind_expression<volatile _Bind<_Signature> > + : public true_type { }; + + /** + * @brief Class template _Bind is always a bind expression. + * @ingroup binders + */ + template<typename _Signature> + struct is_bind_expression<const volatile _Bind<_Signature>> + : public true_type { }; + + /** + * @brief Class template _Bind_result is always a bind expression. + * @ingroup binders + */ + template<typename _Result, typename _Signature> + struct is_bind_expression<_Bind_result<_Result, _Signature>> + : public true_type { }; + + /** + * @brief Class template _Bind_result is always a bind expression. + * @ingroup binders + */ + template<typename _Result, typename _Signature> + struct is_bind_expression<const _Bind_result<_Result, _Signature>> + : public true_type { }; + + /** + * @brief Class template _Bind_result is always a bind expression. + * @ingroup binders + */ + template<typename _Result, typename _Signature> + struct is_bind_expression<volatile _Bind_result<_Result, _Signature>> + : public true_type { }; + + /** + * @brief Class template _Bind_result is always a bind expression. + * @ingroup binders + */ template<typename _Result, typename _Signature> - struct is_bind_expression<_Bind_result<_Result, _Signature> > + struct is_bind_expression<const volatile _Bind_result<_Result, _Signature>> : public true_type { }; // Trait type used to remove std::bind() from overload set via SFINAE Index: include/tr1/functional =================================================================== --- include/tr1/functional (revision 181606) +++ include/tr1/functional (revision 181607) @@ -43,9 +43,20 @@ #include <tr1/functional_hash.h> #include <ext/type_traits.h> #include <bits/move.h> // for std::__addressof +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +# include <type_traits> // for integral_constant, true_type, false_type +#endif namespace std _GLIBCXX_VISIBILITY(default) { +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + template<int> struct _Placeholder; + template<typename> class _Bind; + template<typename, typename> class _Bind_result; +_GLIBCXX_END_NAMESPACE_VERSION +#endif + namespace tr1 { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -847,16 +858,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_END_NAMESPACE_VERSION - /** @namespace std::placeholders - * @brief ISO C++ 0x entities sub namespace for functional. - * - * Define a large number of placeholders. There is no way to - * simplify this with variadic templates, because we're introducing - * unique names for each. + /** @namespace std::tr1::placeholders + * @brief Sub-namespace for tr1/functional. */ namespace placeholders { _GLIBCXX_BEGIN_NAMESPACE_VERSION + /* Define a large number of placeholders. There is no way to + * simplify this with variadic templates, because we're introducing + * unique names for each. + */ namespace { _Placeholder<1> _1; @@ -904,6 +915,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<int _Num> const int is_placeholder<_Placeholder<_Num> >::value; +#ifdef __GXX_EXPERIMENTAL_CXX0X__ + template<int _Num> + struct is_placeholder<std::_Placeholder<_Num>> + : std::integral_constant<int, _Num> + { }; + + template<int _Num> + struct is_placeholder<const std::_Placeholder<_Num>> + : std::integral_constant<int, _Num> + { }; +#endif + /** * Stores a tuple of indices. Used by bind() to extract the elements * in a tuple. @@ -1347,6 +1370,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Signature> const bool is_bind_expression<_Bind<_Signature> >::value; + /// Class template _Bind is always a bind expression. + template<typename _Signature> + struct is_bind_expression<const _Bind<_Signature> > + { static const bool value = true; }; + + template<typename _Signature> + const bool is_bind_expression<const _Bind<_Signature> >::value; + + /// Class template _Bind is always a bind expression. + template<typename _Signature> + struct is_bind_expression<volatile _Bind<_Signature> > + { static const bool value = true; }; + + template<typename _Signature> + const bool is_bind_expression<volatile _Bind<_Signature> >::value; + + /// Class template _Bind is always a bind expression. + template<typename _Signature> + struct is_bind_expression<const volatile _Bind<_Signature> > + { static const bool value = true; }; + + template<typename _Signature> + const bool is_bind_expression<const volatile _Bind<_Signature> >::value; + /// Class template _Bind_result is always a bind expression. template<typename _Result, typename _Signature> struct is_bind_expression<_Bind_result<_Result, _Signature> > @@ -1355,6 +1402,70 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Result, typename _Signature> const bool is_bind_expression<_Bind_result<_Result, _Signature> >::value; + /// Class template _Bind_result is always a bind expression. + template<typename _Result, typename _Signature> + struct is_bind_expression<const _Bind_result<_Result, _Signature> > + { static const bool value = true; }; + + template<typename _Result, typename _Signature> + const bool + is_bind_expression<const _Bind_result<_Result, _Signature> >::value; + + /// Class template _Bind_result is always a bind expression. + template<typename _Result, typename _Signature> + struct is_bind_expression<volatile _Bind_result<_Result, _Signature> > + { static const bool value = true; }; + + template<typename _Result, typename _Signature> + const bool + is_bind_expression<volatile _Bind_result<_Result, _Signature> >::value; + + /// Class template _Bind_result is always a bind expression. + template<typename _Result, typename _Signature> + struct + is_bind_expression<const volatile _Bind_result<_Result, _Signature> > + { static const bool value = true; }; + + template<typename _Result, typename _Signature> + const bool + is_bind_expression<const volatile _Bind_result<_Result, + _Signature> >::value; + +#ifdef __GXX_EXPERIMENTAL_CXX0X__ + template<typename _Signature> + struct is_bind_expression<std::_Bind<_Signature>> + : true_type { }; + + template<typename _Signature> + struct is_bind_expression<const std::_Bind<_Signature>> + : true_type { }; + + template<typename _Signature> + struct is_bind_expression<volatile std::_Bind<_Signature>> + : true_type { }; + + template<typename _Signature> + struct is_bind_expression<const volatile std::_Bind<_Signature>> + : true_type { }; + + template<typename _Result, typename _Signature> + struct is_bind_expression<std::_Bind_result<_Result, _Signature>> + : true_type { }; + + template<typename _Result, typename _Signature> + struct is_bind_expression<const std::_Bind_result<_Result, _Signature>> + : true_type { }; + + template<typename _Result, typename _Signature> + struct is_bind_expression<volatile std::_Bind_result<_Result, _Signature>> + : true_type { }; + + template<typename _Result, typename _Signature> + struct is_bind_expression<const volatile std::_Bind_result<_Result, + _Signature>> + : true_type { }; +#endif + /// bind template<typename _Functor, typename... _ArgTypes> inline @@ -2147,6 +2258,59 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_END_NAMESPACE_VERSION } + +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + template<typename> struct is_placeholder; + + template<int _Num> + struct is_placeholder<tr1::_Placeholder<_Num>> + : integral_constant<int, _Num> + { }; + + template<int _Num> + struct is_placeholder<const tr1::_Placeholder<_Num>> + : integral_constant<int, _Num> + { }; + + template<typename> struct is_bind_expression; + + template<typename _Signature> + struct is_bind_expression<tr1::_Bind<_Signature>> + : true_type { }; + + template<typename _Signature> + struct is_bind_expression<const tr1::_Bind<_Signature>> + : true_type { }; + + template<typename _Signature> + struct is_bind_expression<volatile tr1::_Bind<_Signature>> + : true_type { }; + + template<typename _Signature> + struct is_bind_expression<const volatile tr1::_Bind<_Signature>> + : true_type { }; + + template<typename _Result, typename _Signature> + struct is_bind_expression<tr1::_Bind_result<_Result, _Signature>> + : true_type { }; + + template<typename _Result, typename _Signature> + struct is_bind_expression<const tr1::_Bind_result<_Result, _Signature>> + : true_type { }; + + template<typename _Result, typename _Signature> + struct is_bind_expression<volatile tr1::_Bind_result<_Result, _Signature>> + : true_type { }; + + template<typename _Result, typename _Signature> + struct is_bind_expression<const volatile tr1::_Bind_result<_Result, + _Signature>> + : true_type { }; + +_GLIBCXX_END_NAMESPACE_VERSION +#endif } #endif // _GLIBCXX_TR1_FUNCTIONAL Index: testsuite/tr1/3_function_objects/bind/cv_quals.cc =================================================================== --- testsuite/tr1/3_function_objects/bind/cv_quals.cc (revision 0) +++ testsuite/tr1/3_function_objects/bind/cv_quals.cc (revision 181607) @@ -0,0 +1,53 @@ +// Copyright (C) 2011 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-do compile } +// { dg-options "-std=gnu++0x" } + +#include <tr1/functional> + +struct X +{ + int operator()() const { return 0; } + int operator()() volatile { return 1; } + int operator()() const volatile { return 2; } + void operator()() { }; +}; + +void test01() +{ + static_assert( std::tr1::is_placeholder<__typeof(std::tr1::placeholders::_1)>::value, + "decltype(_1) is a placeholder type" ); + + const auto b0 = std::tr1::bind(X()); + static_assert( std::tr1::is_bind_expression<__typeof(b0)>::value, + "const-qualified wrapper is a bind expression" ); + + volatile auto b1 = std::tr1::bind(X()); + static_assert( std::tr1::is_bind_expression<__typeof(b1)>::value, + "volatile-qualified wrapper is a bind expression" ); + + const volatile auto b2 = std::tr1::bind(X()); + static_assert( std::tr1::is_bind_expression<__typeof(b2)>::value, + "const-volatile-qualified wrapper is a bind expression" ); +} + +int main() +{ + test01(); + return 0; +} Index: testsuite/tr1/3_function_objects/bind/mixed.cc =================================================================== --- testsuite/tr1/3_function_objects/bind/mixed.cc (revision 0) +++ testsuite/tr1/3_function_objects/bind/mixed.cc (revision 181607) @@ -0,0 +1,139 @@ +// { dg-options "-std=gnu++11" } +// 2011-11-20 Jonathan Wakely <jwakely.gcc -at- gmail.com> +// +// Copyright (C) 2011 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/>. + +// 3.6 function object binders +#include <tr1/functional> +#include <functional> +#include <testsuite_hooks.h> + +// std::tr1::bind and std::bind should work together + +namespace p1 = std::placeholders; +namespace p2 = std::tr1::placeholders; + +using std::multiplies; +using std::minus; + +void test01() +{ + static_assert( std::is_placeholder<decltype(p2::_2)>::value == 2, + "TR1 placeholder is a std placeholder" ); + static_assert( std::tr1::is_placeholder<decltype(p1::_1)>::value == 1, + "std placeholder is a TR2 placeholder" ); +} + +void test02() +{ + bool test __attribute__((unused)) = true; + + auto b1 = std::bind(minus<int>(), 6, p2::_2); + auto b2 = std::tr1::bind(minus<int>(), 6, p1::_2); + + int five = 5; + int seven = 7; + + VERIFY( std::tr1::bind(multiplies<int>(), p1::_1, b1)(five, seven) == -5 ); + VERIFY( std::bind(multiplies<int>(), p2::_1, b2)(seven, five) == 7 ); + + VERIFY( std::tr1::bind<int>(multiplies<int>(), p1::_1, b1)(five, seven) == -5 ); + VERIFY( std::bind<int>(multiplies<int>(), p2::_1, b2)(seven, five) == 7 ); + + static_assert( std::is_bind_expression<decltype(b2)>::value, + "TR1 bind expression is a std bind expression" ); + static_assert( std::tr1::is_bind_expression<decltype(b1)>::value, + "std bind expression is a TR2 bind expression" ); + + const auto c1 = b1; + const auto c2 = b2; + + static_assert( std::is_bind_expression<decltype(c2)>::value, + "const TR1 bind expression is a std bind expression" ); + static_assert( std::tr1::is_bind_expression<decltype(c1)>::value, + "const std bind expression is a TR2 bind expression" ); + + volatile auto v1 = b1; + volatile auto v2 = b2; + + static_assert( std::is_bind_expression<decltype(v2)>::value, + "volatile TR1 bind expression is a std bind expression" ); + static_assert( std::tr1::is_bind_expression<decltype(v1)>::value, + "volatile std bind expression is a TR2 bind expression" ); + + const volatile auto cv1 = b1; + const volatile auto cv2 = b2; + + static_assert( std::is_bind_expression<decltype(cv2)>::value, + "const volatile TR1 bind expression is a std bind expression" ); + static_assert( std::tr1::is_bind_expression<decltype(cv1)>::value, + "const volatile std bind expression is a TR2 bind expression" ); +} + +void test03() +{ + bool test __attribute__((unused)) = true; + + auto b1 = std::bind<int>(minus<int>(), 6, p2::_2); + auto b2 = std::tr1::bind<int>(minus<int>(), 6, p1::_2); + + int five = 5; + int seven = 7; + VERIFY( std::tr1::bind(multiplies<int>(), p1::_1, b1)(five, seven) == -5 ); + VERIFY( std::bind(multiplies<int>(), p2::_1, b2)(seven, five) == 7 ); + + VERIFY( std::tr1::bind<int>(multiplies<int>(), p1::_1, b1)(five, seven) == -5 ); + VERIFY( std::bind<int>(multiplies<int>(), p2::_1, b2)(seven, five) == 7 ); + + static_assert( std::is_bind_expression<decltype(b2)>::value, + "TR1 bind<R> expression is a std bind expression" ); + static_assert( std::tr1::is_bind_expression<decltype(b1)>::value, + "std bind<R> expression is a TR2 bind expression" ); + + const auto c1 = b1; + const auto c2 = b2; + + static_assert( std::is_bind_expression<decltype(c2)>::value, + "const TR1 bind<R> expression is a std bind expression" ); + static_assert( std::tr1::is_bind_expression<decltype(c1)>::value, + "const std bind<R> expression is a TR2 bind expression" ); + + volatile auto v1 = b1; + volatile auto v2 = b2; + + static_assert( std::is_bind_expression<decltype(v2)>::value, + "volatile TR1 bind<R> expression is a std bind expression" ); + static_assert( std::tr1::is_bind_expression<decltype(v1)>::value, + "volatile std bind<R> expression is a TR2 bind expression" ); + + const volatile auto cv1 = b1; + const volatile auto cv2 = b2; + + static_assert( std::is_bind_expression<decltype(cv2)>::value, + "const volatile TR1 bind<R> expression is a std bind expression" ); + static_assert( std::tr1::is_bind_expression<decltype(cv1)>::value, + "const volatile std bind<R> expression is a TR2 bind expression" ); +} + +int main() +{ + test01(); + test02(); + test03(); + return 0; +} Index: testsuite/20_util/bind/cv_quals_3.cc =================================================================== --- testsuite/20_util/bind/cv_quals_3.cc (revision 0) +++ testsuite/20_util/bind/cv_quals_3.cc (revision 181607) @@ -0,0 +1,65 @@ +// Copyright (C) 2011 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-do compile } +// { dg-options "-std=gnu++0x" } + +#include <functional> + +struct X +{ + int operator()() const { return 0; } + int operator()() volatile { return 1; } + int operator()() const volatile { return 2; } + void operator()() { }; +}; + +void test01() +{ + static_assert( std::is_placeholder<decltype(std::placeholders::_1)>::value, + "decltype(_1) is a placeholder type" ); + + const auto b0 = std::bind(X()); + static_assert( std::is_bind_expression<decltype(b0)>::value, + "const-qualified wrapper is a bind expression" ); + + volatile auto b1 = std::bind(X()); + static_assert( std::is_bind_expression<decltype(b1)>::value, + "volatile-qualified wrapper is a bind expression" ); + + const volatile auto b2 = std::bind(X()); + static_assert( std::is_bind_expression<decltype(b2)>::value, + "const-volatile-qualified wrapper is a bind expression" ); + + const auto b3 = std::bind<int>(X()); + static_assert( std::is_bind_expression<decltype(b3)>::value, + "const-qualified wrapper is a bind expression" ); + + volatile auto b4 = std::bind<int>(X()); + static_assert( std::is_bind_expression<decltype(b4)>::value, + "volatile-qualified wrapper is a bind expression" ); + + const volatile auto b5 = std::bind<int>(X()); + static_assert( std::is_bind_expression<decltype(b5)>::value, + "const-volatile-qualified wrapper is a bind expression" ); +} + +int main() +{ + test01(); + return 0; +}