Patchwork [v3] support mixing std::bind and tr1::bind

login
register
mail settings
Submitter Jonathan Wakely
Date Nov. 22, 2011, 12:47 a.m.
Message ID <CAH6eHdS=YX8x20KzryDxNSL0vUerNJfGPKDG8QRnw7UpGw80ZQ@mail.gmail.com>
Download mbox | patch
Permalink /patch/126977/
State New
Headers show

Comments

Jonathan Wakely - Nov. 22, 2011, 12:47 a.m.
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.

Patch

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;
+}