From 09fc4c759b657b3b5f6a5fdf077c865d834d2906 Mon Sep 17 00:00:00 2001 From: Krystyna Lopez Date: Sat, 4 Jan 2020 22:47:03 -0500 Subject: [PATCH 1/3] Fix #239: Improve _Invoke_traits throughput --- stl/inc/type_traits | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/type_traits b/stl/inc/type_traits index 1f8a5c69f0..8c78bfe78b 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1683,11 +1683,11 @@ struct _Invoke_traits { // selected when _Callable isn't callable with _Args }; template -struct _Invoke_traits()...))>, +struct _Invoke_traits::_Call(_STD declval<_Types>()...))>, _Types...> { // selected when _Callable is callable with _Args - using type = decltype(_STD invoke(_STD declval<_Types>()...)); + using type = decltype(_STD _Invoker<_Types...>::_Call(_STD declval<_Types>()...)); using _Is_invocable = true_type; - using _Is_nothrow_invocable = bool_constant()...))>; + using _Is_nothrow_invocable = bool_constant::_Call(_STD declval<_Types>()...))>; template using _Is_invocable_r = bool_constant, is_convertible>>; template From 88a7b4c6dc1024f25c5d2130ba769544ed481487 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 8 Jan 2020 20:00:54 -0800 Subject: [PATCH 2/3] Remove unnecessary _STD qualification. --- stl/inc/type_traits | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/type_traits b/stl/inc/type_traits index 8c78bfe78b..dc5d5d06a0 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1683,11 +1683,11 @@ struct _Invoke_traits { // selected when _Callable isn't callable with _Args }; template -struct _Invoke_traits::_Call(_STD declval<_Types>()...))>, +struct _Invoke_traits::_Call(_STD declval<_Types>()...))>, _Types...> { // selected when _Callable is callable with _Args - using type = decltype(_STD _Invoker<_Types...>::_Call(_STD declval<_Types>()...)); + using type = decltype(_Invoker<_Types...>::_Call(_STD declval<_Types>()...)); using _Is_invocable = true_type; - using _Is_nothrow_invocable = bool_constant::_Call(_STD declval<_Types>()...))>; + using _Is_nothrow_invocable = bool_constant::_Call(_STD declval<_Types>()...))>; template using _Is_invocable_r = bool_constant, is_convertible>>; template From a660e02c2c3813d9f52c33e24d7f354ed6cd88a6 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 25 Mar 2020 19:06:54 -0700 Subject: [PATCH 3/3] Merge with GH-585. --- stl/inc/type_traits | 78 +++++++++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 20 deletions(-) diff --git a/stl/inc/type_traits b/stl/inc/type_traits index 7dc37d718e..252671ccae 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1689,8 +1689,36 @@ template using is_nothrow_convertible = _Is_nothrow_convertible<_From, _To>; #endif // _HAS_CXX20 +template +struct _Invoke_traits_zero { + // selected when _Callable isn't callable with zero _Args + using _Is_invocable = false_type; + using _Is_nothrow_invocable = false_type; + template + using _Is_invocable_r = false_type; + template + using _Is_nothrow_invocable_r = false_type; +}; + +template +using _Decltype_invoke_zero = decltype(_STD declval<_Callable>()()); + +template +struct _Invoke_traits_zero>, _Callable> { + // selected when _Callable is callable with zero _Args + using type = _Decltype_invoke_zero<_Callable>; + using _Is_invocable = true_type; + using _Is_nothrow_invocable = bool_constant()())>; + template + using _Is_invocable_r = bool_constant, is_convertible>>; + template + using _Is_nothrow_invocable_r = bool_constant< + conjunction_v<_Is_nothrow_invocable, disjunction, _Is_nothrow_convertible>>>; +}; + template -struct _Invoke_traits { // selected when _Callable isn't callable with _Args +struct _Invoke_traits_nonzero { + // selected when _Callable isn't callable with nonzero _Args using _Is_invocable = false_type; using _Is_nothrow_invocable = false_type; template @@ -1699,12 +1727,18 @@ struct _Invoke_traits { // selected when _Callable isn't callable with _Args using _Is_nothrow_invocable_r = false_type; }; -template -struct _Invoke_traits::_Call(_STD declval<_Types>()...))>, - _Types...> { // selected when _Callable is callable with _Args - using type = decltype(_Invoker<_Types...>::_Call(_STD declval<_Types>()...)); +template +using _Decltype_invoke_nonzero = decltype( + _Invoker1<_Callable, _Ty1>::_Call(_STD declval<_Callable>(), _STD declval<_Ty1>(), _STD declval<_Types2>()...)); + +template +struct _Invoke_traits_nonzero>, _Callable, _Ty1, + _Types2...> { + // selected when _Callable is callable with nonzero _Args + using type = _Decltype_invoke_nonzero<_Callable, _Ty1, _Types2...>; using _Is_invocable = true_type; - using _Is_nothrow_invocable = bool_constant::_Call(_STD declval<_Types>()...))>; + using _Is_nothrow_invocable = bool_constant::_Call( + _STD declval<_Callable>(), _STD declval<_Ty1>(), _STD declval<_Types2>()...))>; template using _Is_invocable_r = bool_constant, is_convertible>>; template @@ -1712,6 +1746,10 @@ struct _Invoke_traits::_Call(_STD declval<_T conjunction_v<_Is_nothrow_invocable, disjunction, _Is_nothrow_convertible>>>; }; +template +using _Select_invoke_traits = conditional_t, + _Invoke_traits_nonzero>; + #if _HAS_DEPRECATED_RESULT_OF // STRUCT TEMPLATE result_of template @@ -1720,10 +1758,10 @@ struct _CXX17_DEPRECATE_RESULT_OF result_of { // explain usage "result_of instead."); }; -#define _RESULT_OF(CALL_OPT, X1, X2, X3) \ - template \ - struct _CXX17_DEPRECATE_RESULT_OF result_of<_Callable CALL_OPT(_Args...)> \ - : _Invoke_traits { /* template to determine result of call operation */ \ +#define _RESULT_OF(CALL_OPT, X1, X2, X3) \ + template \ + struct _CXX17_DEPRECATE_RESULT_OF result_of<_Callable CALL_OPT(_Args...)> \ + : _Select_invoke_traits<_Callable, _Args...> { /* template to determine result of call operation */ \ }; _NON_MEMBER_CALL(_RESULT_OF, X1, X2, X3) @@ -1736,10 +1774,10 @@ _STL_RESTORE_DEPRECATED_WARNING #endif // _HAS_DEPRECATED_RESULT_OF template -using _Invoke_result_t = typename _Invoke_traits::type; +using _Invoke_result_t = typename _Select_invoke_traits<_Callable, _Args...>::type; template -using _Is_invocable_r_ = typename _Invoke_traits::template _Is_invocable_r<_Rx>; +using _Is_invocable_r_ = typename _Select_invoke_traits<_Callable, _Args...>::template _Is_invocable_r<_Rx>; template struct _Is_invocable_r : _Is_invocable_r_<_Rx, _Callable, _Args...> { @@ -1749,30 +1787,30 @@ struct _Is_invocable_r : _Is_invocable_r_<_Rx, _Callable, _Args...> { #if _HAS_CXX17 // STRUCT TEMPLATE invoke_result template -struct invoke_result : _Invoke_traits { +struct invoke_result : _Select_invoke_traits<_Callable, _Args...> { // determine the result type of invoking _Callable with _Args }; template -using invoke_result_t = typename _Invoke_traits::type; +using invoke_result_t = typename _Select_invoke_traits<_Callable, _Args...>::type; // STRUCT TEMPLATE is_invocable template -struct is_invocable : _Invoke_traits::_Is_invocable { +struct is_invocable : _Select_invoke_traits<_Callable, _Args...>::_Is_invocable { // determines whether _Callable is callable with _Args }; template -inline constexpr bool is_invocable_v = _Invoke_traits::_Is_invocable::value; +inline constexpr bool is_invocable_v = _Select_invoke_traits<_Callable, _Args...>::_Is_invocable::value; // STRUCT TEMPLATE is_nothrow_invocable template -struct is_nothrow_invocable : _Invoke_traits::_Is_nothrow_invocable { +struct is_nothrow_invocable : _Select_invoke_traits<_Callable, _Args...>::_Is_nothrow_invocable { // determines whether _Callable is nothrow-callable with _Args }; template -inline constexpr bool is_nothrow_invocable_v = _Invoke_traits::_Is_nothrow_invocable::value; +inline constexpr bool is_nothrow_invocable_v = _Select_invoke_traits<_Callable, _Args...>::_Is_nothrow_invocable::value; // STRUCT TEMPLATE is_invocable_r template @@ -1785,13 +1823,13 @@ inline constexpr bool is_invocable_r_v = _Is_invocable_r_<_Rx, _Callable, _Args. // STRUCT TEMPLATE is_nothrow_invocable_r template -struct is_nothrow_invocable_r : _Invoke_traits::template _Is_nothrow_invocable_r<_Rx> { +struct is_nothrow_invocable_r : _Select_invoke_traits<_Callable, _Args...>::template _Is_nothrow_invocable_r<_Rx> { // determines whether _Callable is nothrow-callable with _Args and return type _Rx }; template inline constexpr bool is_nothrow_invocable_r_v = - _Invoke_traits::template _Is_nothrow_invocable_r<_Rx>::value; + _Select_invoke_traits<_Callable, _Args...>::template _Is_nothrow_invocable_r<_Rx>::value; #endif // _HAS_CXX17 #if _HAS_CXX20