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
