EricWF created this revision.
EricWF added a reviewer: mclow.lists.
EricWF added a subscriber: cfe-commits.

This patch is an alternate approach to D9730

std::experimental::apply requires a constexpr implementation of INVOKE(...). 
Simply marking the current implementation of __invoke as constexpr will break 
existing code due to CWG issue #1581. For this reason we should add a separate 
function called __invoke_constexpr to be used where constexpr is required.

This patch adds a `__invoke_constexpr` function that mirrors `__invoke`.

I chose not to generate invoke functions using macros because of the amount of 
code that would have to be within a macro block. It also is likely to yield bad 
error messages.

This patch also re-enables constexpr support for std::experimental::apply.

Also See:
https://llvm.org/bugs/show_bug.cgi?id=23141
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1581

http://reviews.llvm.org/D11329

Files:
  include/experimental/tuple
  include/type_traits
  test/std/experimental/utilities/tuple/tuple.apply/constexpr_types.pass.cpp

Index: test/std/experimental/utilities/tuple/tuple.apply/constexpr_types.pass.cpp
===================================================================
--- test/std/experimental/utilities/tuple/tuple.apply/constexpr_types.pass.cpp
+++ test/std/experimental/utilities/tuple/tuple.apply/constexpr_types.pass.cpp
@@ -9,11 +9,6 @@
 
 // UNSUPPORTED: c++98, c++03, c++11
 
-// TODO(ericwf)
-// constexpr support temporarily reverted due to bug:
-// https://llvm.org/bugs/show_bug.cgi?id=23141
-// XFAIL: *
-
 // <experimental/tuple>
 
 // template <class F, class T> constexpr decltype(auto) apply(F &&, T &&)
Index: include/type_traits
===================================================================
--- include/type_traits
+++ include/type_traits
@@ -3450,6 +3450,51 @@
 {
 };
 
+// INVOKE metaprogramming support
+
+template <class _Tp>
+struct __member_class {};
+
+template <class _Ret, class _Class>
+struct __member_class<_Ret _Class::*> { typedef _Class type; };
+
+template <class _Fp>
+struct __invoke_mem_type : integral_constant<int,
+    is_member_function_pointer<_Fp>::value ? 1 :
+        (is_member_object_pointer<_Fp>::value ? 2 : 0)>
+{};
+
+template <class _Fp, class _A0, bool = __invoke_mem_type<_Fp>::value != 0>
+struct __invoke_is_base_of : false_type {};
+
+template <class _Fp, class _A0>
+struct __invoke_is_base_of<_Fp, _A0, true>
+    : is_base_of<typename __member_class<_Fp>::type, _A0>
+{};
+
+template <class _Fp, class _A0, int = __invoke_mem_type<
+                                    typename remove_cv<typename remove_reference<_Fp>::type>::type
+                                >::value,
+                                bool = __invoke_is_base_of<
+                                    typename remove_cv<typename remove_reference<_Fp>::type>::type,
+                                    typename remove_reference<_A0>::type
+                                >::value>
+struct __invoke_enable_if {};
+
+template <class _Fp, class _A0>
+struct __invoke_enable_if<_Fp, _A0, 1, true> { typedef void _Bullet1; };
+
+template <class _Fp, class _A0>
+struct __invoke_enable_if<_Fp, _A0, 1, false> { typedef void _Bullet2; };
+
+template <class _Fp, class _A0>
+struct __invoke_enable_if<_Fp, _A0, 2, true> { typedef void _Bullet3; };
+
+template <class _Fp, class _A0>
+struct __invoke_enable_if<_Fp, _A0, 2, false> { typedef void _Bullet4; };
+
+
+
 // __invoke forward declarations
 
 // fall back - none of the bullets
@@ -3459,70 +3504,75 @@
 __invoke(__any, _Args&& ...__args)
     -> __nat;
 
-// bullets 1 and 2
-
 template <class _Fp, class _A0, class ..._Args,
-            class = typename enable_if
-            <
-                is_member_function_pointer<typename remove_reference<_Fp>::type>::value &&
-                is_base_of<typename remove_reference<typename __member_pointer_traits<typename remove_reference<_Fp>::type>::_ClassType>::type,
-                           typename remove_reference<_A0>::type>::value
-            >::type
-         >
+          class = typename __invoke_enable_if<_Fp, _A0>::_Bullet1>
 _LIBCPP_INLINE_VISIBILITY
-auto
-__invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
+auto __invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
     -> decltype((_VSTD::forward<_A0>(__a0).*__f)(_VSTD::forward<_Args>(__args)...));
 
 template <class _Fp, class _A0, class ..._Args,
-            class = typename enable_if
-            <
-                is_member_function_pointer<typename remove_reference<_Fp>::type>::value &&
-                !is_base_of<typename remove_reference<typename __member_pointer_traits<typename remove_reference<_Fp>::type>::_ClassType>::type,
-                           typename remove_reference<_A0>::type>::value
-            >::type
-         >
+          class = typename __invoke_enable_if<_Fp, _A0>::_Bullet2>
 _LIBCPP_INLINE_VISIBILITY
-auto
-__invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
+auto __invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
     -> decltype(((*_VSTD::forward<_A0>(__a0)).*__f)(_VSTD::forward<_Args>(__args)...));
 
-// bullets 3 and 4
-
 template <class _Fp, class _A0,
-            class = typename enable_if
-            <
-                is_member_object_pointer<typename remove_reference<_Fp>::type>::value &&
-                is_base_of<typename __member_pointer_traits<typename remove_reference<_Fp>::type>::_ClassType,
-                           typename remove_reference<_A0>::type>::value
-            >::type
-         >
+          class = typename __invoke_enable_if<_Fp, _A0>::_Bullet3>
 _LIBCPP_INLINE_VISIBILITY
-auto
-__invoke(_Fp&& __f, _A0&& __a0)
+auto __invoke(_Fp&& __f, _A0&& __a0)
     -> decltype(_VSTD::forward<_A0>(__a0).*__f);
 
 template <class _Fp, class _A0,
-            class = typename enable_if
-            <
-                is_member_object_pointer<typename remove_reference<_Fp>::type>::value &&
-                !is_base_of<typename __member_pointer_traits<typename remove_reference<_Fp>::type>::_ClassType,
-                           typename remove_reference<_A0>::type>::value
-            >::type
-         >
+          class = typename __invoke_enable_if<_Fp, _A0>::_Bullet4>
 _LIBCPP_INLINE_VISIBILITY
-auto
-__invoke(_Fp&& __f, _A0&& __a0)
+auto __invoke(_Fp&& __f, _A0&& __a0)
     -> decltype((*_VSTD::forward<_A0>(__a0)).*__f);
 
-// bullet 5
-
-template <class _Fp, class ..._Args>
+template <class _Fp, class ..._Args> // bullet 5
 _LIBCPP_INLINE_VISIBILITY
-auto
-__invoke(_Fp&& __f, _Args&& ...__args)
+auto __invoke(_Fp&& __f, _Args&& ...__args)
     -> decltype(_VSTD::forward<_Fp>(__f)(_VSTD::forward<_Args>(__args)...));
 
+// __invoke_constexpr
+
+template <class _Fp, class _A0, class ..._Args,
+          class = typename __invoke_enable_if<_Fp, _A0>::_Bullet1>
+_LIBCPP_INLINE_VISIBILITY
+_LIBCPP_CONSTEXPR
+auto __invoke_constexpr(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
+    -> decltype((_VSTD::forward<_A0>(__a0).*__f)(_VSTD::forward<_Args>(__args)...))
+       { return (_VSTD::forward<_A0>(__a0).*__f)(_VSTD::forward<_Args>(__args)...); }
+
+template <class _Fp, class _A0, class ..._Args,
+          class = typename __invoke_enable_if<_Fp, _A0>::_Bullet2>
+_LIBCPP_INLINE_VISIBILITY
+_LIBCPP_CONSTEXPR
+auto __invoke_constexpr(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
+    -> decltype(((*_VSTD::forward<_A0>(__a0)).*__f)(_VSTD::forward<_Args>(__args)...))
+       { return ((*_VSTD::forward<_A0>(__a0)).*__f)(_VSTD::forward<_Args>(__args)...); }
+
+template <class _Fp, class _A0,
+          class = typename __invoke_enable_if<_Fp, _A0>::_Bullet3>
+_LIBCPP_INLINE_VISIBILITY
+_LIBCPP_CONSTEXPR
+auto __invoke_constexpr(_Fp&& __f, _A0&& __a0)
+    -> decltype(_VSTD::forward<_A0>(__a0).*__f)
+       { return _VSTD::forward<_A0>(__a0).*__f; }
+
+template <class _Fp, class _A0,
+          class = typename __invoke_enable_if<_Fp, _A0>::_Bullet4>
+_LIBCPP_INLINE_VISIBILITY
+auto __invoke_constexpr(_Fp&& __f, _A0&& __a0)
+    -> decltype((*_VSTD::forward<_A0>(__a0)).*__f)
+       { return (*_VSTD::forward<_A0>(__a0)).*__f; }
+
+template <class _Fp, class ..._Args> // bullet 5
+_LIBCPP_INLINE_VISIBILITY
+_LIBCPP_CONSTEXPR
+auto __invoke_constexpr(_Fp&& __f, _Args&& ...__args)
+    -> decltype(_VSTD::forward<_Fp>(__f)(_VSTD::forward<_Args>(__args)...))
+       { return _VSTD::forward<_Fp>(__f)(_VSTD::forward<_Args>(__args)...); }
+
 // __invokable
 
 template <class _Fp, class ..._Args>
Index: include/experimental/tuple
===================================================================
--- include/experimental/tuple
+++ include/experimental/tuple
@@ -41,6 +41,7 @@
 #if _LIBCPP_STD_VER > 11
 
 # include <tuple>
+# include <type_traits>
 # include <utility>
 # include <__functional_base>
 
@@ -56,10 +57,10 @@
 #endif
 
 template <class _Fn, class _Tuple, size_t ..._Id>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
 decltype(auto) __apply_tuple_impl(_Fn && __f, _Tuple && __t,
                                   integer_sequence<size_t, _Id...>) {
-    return _VSTD::__invoke(
+    return _VSTD::__invoke_constexpr(
         _VSTD::forward<_Fn>(__f),
         _VSTD::get<_Id>(_VSTD::forward<_Tuple>(__t))...
     );
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to