[c++0x patch] allow std::bind<void>

Jonathan Wakely jwakely.gcc@gmail.com
Thu Dec 24 14:18:00 GMT 2009


This patch fixes the included testcase, which failed in two ways.

Firstly, overload resolution for bind<void>(...) tries to match the
first overload of bind, causing an invalid instantiation in a context
where SFINAE doesn't apply, producing:
error: forming reference to void
Fixed by adding a valid specialisation so that overload resolution can proceed.

Secondly, if the bound function returns non-void we instantiate something like:

template <typename>
struct Bind_result {

    template<typename... Args>
        void
        operator()(Args... a)
        { return _M_fn(a); }  // error
};

which produces:
error: return-statement with a value, in function returning 'void'
Fixed by overloading the call functions and using SFINAE on
is_void<Res> to enable/disable overloads.

        * include/std/functional (bind): Avoid invalid instantiations
        for bind<void>.
        * testsuite/20_util/bind/conv_result.cc: New.

Tested x86_64/Linux.  I plan to commit this later today.
-------------- next part --------------
Index: include/std/functional
===================================================================
--- include/std/functional	(revision 155456)
+++ include/std/functional	(working copy)
@@ -1130,6 +1130,16 @@ namespace std
       { return type(__pm); }
     };
 
+  // Specialization needed to prevent "forming reference to void" errors when
+  // bind<void>() is called, because argument deduction instantiates
+  // _Maybe_wrap_member_pointer<void> outside the immediate context where
+  // SFINAE applies.
+  template<>
+    struct _Maybe_wrap_member_pointer<void>
+    {
+      typedef void type;
+    };
+
   /// Type of the function object returned from bind().
   template<typename _Signature>
     struct _Bind;
@@ -1262,44 +1272,93 @@ namespace std
       _Functor _M_f;
       tuple<_Bound_args...> _M_bound_args;
 
+      // sfinae types
+      template<typename _Res>
+        struct __enable_if_void : enable_if<is_void<_Res>::value, int> { };
+      template<typename _Res>
+        struct __disable_if_void : enable_if<!is_void<_Res>::value, int> { };
+
       // Call unqualified
-      template<typename... _Args, int... _Indexes>
+      template<typename _Res, typename... _Args, int... _Indexes>
         _Result
-        __call(const tuple<_Args...>& __args, _Index_tuple<_Indexes...>)
+        __call(const tuple<_Args...>& __args, _Index_tuple<_Indexes...>,
+            typename __disable_if_void<_Res>::type = 0)
         {
           return _M_f(_Mu<_Bound_args>()
                       (get<_Indexes>(_M_bound_args), __args)...);
         }
 
+      // Call unqualified, return void
+      template<typename _Res, typename... _Args, int... _Indexes>
+        void
+        __call(const tuple<_Args...>& __args, _Index_tuple<_Indexes...>,
+            typename __enable_if_void<_Res>::type = 0)
+        {
+          _M_f(_Mu<_Bound_args>()
+                      (get<_Indexes>(_M_bound_args), __args)...);
+        }
+
       // Call as const
-      template<typename... _Args, int... _Indexes>
+      template<typename _Res, typename... _Args, int... _Indexes>
         _Result
-        __call(const tuple<_Args...>& __args, _Index_tuple<_Indexes...>) const
+        __call(const tuple<_Args...>& __args, _Index_tuple<_Indexes...>,
+            typename __disable_if_void<_Res>::type = 0) const
         {
           return _M_f(_Mu<_Bound_args>()
                       (get<_Indexes>(_M_bound_args), __args)...);
         }
 
+      // Call as const, return void
+      template<typename _Res, typename... _Args, int... _Indexes>
+        void
+        __call(const tuple<_Args...>& __args, _Index_tuple<_Indexes...>,
+            typename __enable_if_void<_Res>::type = 0) const
+        {
+          _M_f(_Mu<_Bound_args>()
+                      (get<_Indexes>(_M_bound_args), __args)...);
+        }
+
       // Call as volatile
-      template<typename... _Args, int... _Indexes>
+      template<typename _Res, typename... _Args, int... _Indexes>
         _Result
-        __call(const tuple<_Args...>& __args, 
-               _Index_tuple<_Indexes...>) volatile
+        __call(const tuple<_Args...>& __args, _Index_tuple<_Indexes...>,
+            typename __disable_if_void<_Res>::type = 0) volatile
         {
           return _M_f(_Mu<_Bound_args>()
                       (get<_Indexes>(_M_bound_args), __args)...);
         }
 
+      // Call as volatile, return void
+      template<typename _Res, typename... _Args, int... _Indexes>
+        void
+        __call(const tuple<_Args...>& __args, _Index_tuple<_Indexes...>,
+            typename __enable_if_void<_Res>::type = 0) volatile
+        {
+          _M_f(_Mu<_Bound_args>()
+                      (get<_Indexes>(_M_bound_args), __args)...);
+        }
+
       // Call as const volatile
-      template<typename... _Args, int... _Indexes>
+      template<typename _Res, typename... _Args, int... _Indexes>
         _Result
-        __call(const tuple<_Args...>& __args, 
-               _Index_tuple<_Indexes...>) const volatile
+        __call(const tuple<_Args...>& __args, _Index_tuple<_Indexes...>,
+            typename __disable_if_void<_Res>::type = 0) const volatile
         {
           return _M_f(_Mu<_Bound_args>()
                       (get<_Indexes>(_M_bound_args), __args)...);
         }
 
+      // Call as const volatile, return void
+      template<typename _Res, typename... _Args, int... _Indexes>
+        void
+        __call(const tuple<_Args...>& __args, 
+               _Index_tuple<_Indexes...>,
+            typename __enable_if_void<_Res>::type = 0) const volatile
+        {
+          _M_f(_Mu<_Bound_args>()
+                      (get<_Indexes>(_M_bound_args), __args)...);
+        }
+
     public:
       typedef _Result result_type;
 
@@ -1312,7 +1371,7 @@ namespace std
         result_type
         operator()(_Args&... __args)
         {
-          return this->__call(tie(__args...), _Bound_indexes());
+          return this->__call<_Result>(tie(__args...), _Bound_indexes());
         }
 
       // Call as const
@@ -1320,7 +1379,7 @@ namespace std
         result_type
         operator()(_Args&... __args) const
         {
-          return this->__call(tie(__args...), _Bound_indexes());
+          return this->__call<_Result>(tie(__args...), _Bound_indexes());
         }
 
       // Call as volatile
@@ -1328,7 +1387,7 @@ namespace std
         result_type
         operator()(_Args&... __args) volatile
         {
-          return this->__call(tie(__args...), _Bound_indexes());
+          return this->__call<_Result>(tie(__args...), _Bound_indexes());
         }
 
       // Call as const volatile
@@ -1336,7 +1395,7 @@ namespace std
         result_type
         operator()(_Args&... __args) const volatile
         {
-          return this->__call(tie(__args...), _Bound_indexes());
+          return this->__call<_Result>(tie(__args...), _Bound_indexes());
         }
     };
 
Index: testsuite/20_util/bind/conv_result.cc
===================================================================
--- testsuite/20_util/bind/conv_result.cc	(revision 0)
+++ testsuite/20_util/bind/conv_result.cc	(revision 0)
@@ -0,0 +1,49 @@
+// { dg-options "-std=gnu++0x" }
+// Copyright (C) 2009 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/>.
+
+// 20.7.11 Function template bind
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+struct X
+{
+  typedef int result_type;
+  int operator()(int i) const { return i+1; }
+  bool b;
+};
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+  using std::bind;
+  using std::ref;
+  ::X x = { true };
+
+  // test bind<R> form
+  bind<void>(ref(x), 1)();
+  VERIFY( bind<long>(ref(x), 1)() == 2 );
+  bind<void>(&::X::b, ref(x))();
+  VERIFY( bind<int>(&::X::b, ref(x))() == 1 );
+}
+
+int main()
+{
+  test01();
+  return 0;
+}


More information about the Libstdc++ mailing list