[libc++] Request for review regarding std::bind

Howard Hinnant hhinnant at apple.com
Tue Feb 19 12:11:14 PST 2013


I'm looking at:

http://llvm.org/bugs/show_bug.cgi?id=15295

I think I've got a fix, but I find bind terribly confusing.  I think a review is in order.  Here is the patch I'm proposing:

Index: include/functional
===================================================================
--- include/functional	(revision 175515)
+++ include/functional	(working copy)
@@ -1624,16 +1624,38 @@
     : public ____mu_return<_Ti,
                            __is_reference_wrapper<_Ti>::value,
                            is_bind_expression<_Ti>::value,
-                           0 < is_placeholder<_Ti>::value,
+                           0 < is_placeholder<_Ti>::value &&
+                           is_placeholder<_Ti>::value <= tuple_size<_TupleUj>::value,
                            _TupleUj>
 {
 };
 
 template <class _Fp, class _BoundArgs, class _TupleUj>
+struct _is_valid_bind_return
+{
+    static const bool value = false;
+};
+
+template <class _Fp, class ..._BoundArgs, class _TupleUj>
+struct _is_valid_bind_return<_Fp, tuple<_BoundArgs...>, _TupleUj>
+{
+    static const bool value = __invokable<_Fp,
+                    typename __mu_return<_BoundArgs, _TupleUj>::type...>::value;
+};
+
+template <class _Fp, class ..._BoundArgs, class _TupleUj>
+struct _is_valid_bind_return<_Fp, const tuple<_BoundArgs...>, _TupleUj>
+{
+    static const bool value = __invokable<_Fp,
+                    typename __mu_return<const _BoundArgs, _TupleUj>::type...>::value;
+};
+
+template <class _Fp, class _BoundArgs, class _TupleUj,
+          bool = _is_valid_bind_return<_Fp, _BoundArgs, _TupleUj>::value>
 struct __bind_return;
 
 template <class _Fp, class ..._BoundArgs, class _TupleUj>
-struct __bind_return<_Fp, tuple<_BoundArgs...>, _TupleUj>
+struct __bind_return<_Fp, tuple<_BoundArgs...>, _TupleUj, true>
 {
     typedef typename __invoke_of
     <
@@ -1647,7 +1669,7 @@
 };
 
 template <class _Fp, class ..._BoundArgs, class _TupleUj>
-struct __bind_return<_Fp, const tuple<_BoundArgs...>, _TupleUj>
+struct __bind_return<_Fp, const tuple<_BoundArgs...>, _TupleUj, true>
 {
     typedef typename __invoke_of
     <
@@ -1673,8 +1695,10 @@
 class __bind
     : public __weak_result_type<typename decay<_Fp>::type>
 {
+protected:
     typedef typename decay<_Fp>::type _Fd;
     typedef tuple<typename decay<_BoundArgs>::type...> _Td;
+private:
     _Fd __f_;
     _Td __bound_args_;
 
@@ -1731,7 +1755,7 @@
 
     template <class ..._Args>
         _LIBCPP_INLINE_VISIBILITY
-        typename __bind_return<_Fd, _Td, tuple<_Args&&...> >::type
+        typename __bind_return<const _Fd, const _Td, tuple<_Args&&...> >::type
         operator()(_Args&& ...__args) const
         {
             return __apply_functor(__f_, __bound_args_, __indices(),
@@ -1747,6 +1771,8 @@
     : public __bind<_Fp, _BoundArgs...>
 {
     typedef __bind<_Fp, _BoundArgs...> base;
+    typedef typename base::_Fd _Fd;
+    typedef typename base::_Td _Td;
 public:
     typedef _Rp result_type;
 
@@ -1784,7 +1810,12 @@
 
     template <class ..._Args>
         _LIBCPP_INLINE_VISIBILITY
-        result_type
+        typename enable_if
+        <
+            is_convertible<typename __bind_return<_Fd, _Td, tuple<_Args&&...> >::type,
+                           result_type>::value,
+            result_type
+        >::type
         operator()(_Args&& ...__args)
         {
             return base::operator()(_VSTD::forward<_Args>(__args)...);
@@ -1792,7 +1823,12 @@
 
     template <class ..._Args>
         _LIBCPP_INLINE_VISIBILITY
-        result_type
+        typename enable_if
+        <
+            is_convertible<typename __bind_return<const _Fd, const _Td, tuple<_Args&&...> >::type,
+                           result_type>::value,
+            result_type
+        >::type
         operator()(_Args&& ...__args) const
         {
             return base::operator()(_VSTD::forward<_Args>(__args)...);

In a nutshell, I'm trying to SFINAE-out the operator()()'s of __bind/__bind_r function objects returned from bind if the arguments to the operator()() don't satisfy the requirements in [func.bind.bind].  The intent is to allow bind to work in a SFINAE as requested in the bug report.

With this patch, the example in the bug report works, and all of the unit tests pass.  However if you uncomment the line marked // Prints 0 in the bug report, and comment out the previous line, that test fails.  The reason that test fails is because that bind object has no valid operator()(), they are all SFINAE'd out.

If there's anyone out there with a penchant for bind, more eyes are welcome...

Howard




More information about the cfe-commits mailing list