[libcxx] P0604, invoke_result and is_invocable

Summary:
Introduce a new form of `result_of` without function type encoding.

Rename and split `is_callable/is_nothrow_callable` into `is_invocable/is_nothrow_invocable/is_invocable_r/is_nothrow_invocable_r` (and associated types accordingly)

Change function type encoding of previous `is_callable/is_nothrow_callable` traits to conventional template type parameter lists.


Reviewers: EricWF, mclow.lists, bebuch

Reviewed By: EricWF, bebuch

Subscribers: lichray, bebuch, cfe-commits

Differential Revision: https://reviews.llvm.org/D38831

llvm-svn: 320509
Cr-Mirrored-From: sso://chromium.googlesource.com/_direct/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: bcde6e715ef0fd2ae3e092b4104cc9c79bd73cf6
diff --git a/include/type_traits b/include/type_traits
index 8485c8c..60b5dec 100644
--- a/include/type_traits
+++ b/include/type_traits
@@ -137,13 +137,11 @@
     template <class Base, class Derived> struct is_base_of;
     template <class From, class To> struct is_convertible;
 
-    template <class, class R = void> struct is_callable; // not defined
-    template <class Fn, class... ArgTypes, class R>
-      struct is_callable<Fn(ArgTypes...), R>;
+    template <class Fn, class... ArgTypes> struct is_invocable;
+    template <class R, class Fn, class... ArgTypes> struct is_invocable_r;
 
-    template <class, class R = void> struct is_nothrow_callable; // not defined
-    template <class Fn, class... ArgTypes, class R>
-      struct is_nothrow_callable<Fn(ArgTypes...), R>;
+    template <class Fn, class... ArgTypes> struct is_nothrow_invocable;
+    template <class R, class Fn, class... ArgTypes> struct is_nothrow_invocable_r;
 
     // Alignment properties and transformations:
     template <class T> struct alignment_of;
@@ -157,6 +155,7 @@
     template <class T> struct underlying_type;
     template <class> class result_of; // undefined
     template <class Fn, class... ArgTypes> class result_of<Fn(ArgTypes...)>;
+    template <class Fn, class... ArgTypes> struct invoke_result;  // C++17
 
     // const-volatile modifications:
     template <class T>
@@ -215,8 +214,10 @@
       using common_type_t     = typename common_type<T...>::type;  // C++14
     template <class T>
       using underlying_type_t = typename underlying_type<T>::type;  // C++14
-    template <class F, class... ArgTypes>
-      using result_of_t       = typename result_of<F(ArgTypes...)>::type;  // C++14
+    template <class T>
+      using result_of_t       = typename result_of<T>::type;  // C++14
+    template <class Fn, class... ArgTypes>
+      using invoke_result_t   = typename invoke_result<Fn, ArgTypes...>::type;  // C++17
 
     template <class...>
       using void_t = void;   // C++17
@@ -370,10 +371,14 @@
         = is_base_of<Base, Derived>::value;                              // C++17
       template <class From, class To> constexpr bool is_convertible_v
         = is_convertible<From, To>::value;                               // C++17
-      template <class T, class R = void> constexpr bool is_callable_v
-        = is_callable<T, R>::value;                                      // C++17
-      template <class T, class R = void> constexpr bool is_nothrow_callable_v
-        = is_nothrow_callable<T, R>::value;                              // C++17
+      template <class Fn, class... ArgTypes> constexpr bool is_invocable_v
+        = is_invocable<Fn, ArgTypes...>::value;                          // C++17
+      template <class R, class Fn, class... ArgTypes> constexpr bool is_invocable_r_v
+        = is_invocable_r<R, Fn, ArgTypes...>::value;                     // C++17
+      template <class Fn, class... ArgTypes> constexpr bool is_nothrow_invocable_v
+        = is_nothrow_invocable<Fn, ArgTypes...>::value;                  // C++17
+      template <class R, class Fn, class... ArgTypes> constexpr bool is_nothrow_invocable_r_v
+        = is_nothrow_invocable_r<R, Fn, ArgTypes...>::value;             // C++17
 
       // [meta.logical], logical operator traits:
       template<class... B> struct conjunction;                           // C++17
@@ -4402,6 +4407,13 @@
     >;
 
 template <class _Fp, class ..._Args>
+using __nothrow_invokable =
+    __nothrow_invokable_r_imp<
+            __invokable<_Fp, _Args...>::value,
+            true, void, _Fp, _Args...
+    >;
+
+template <class _Fp, class ..._Args>
 struct __invoke_of
     : public enable_if<
         __invokable<_Fp, _Args...>::value,
@@ -4423,30 +4435,48 @@
 
 #if _LIBCPP_STD_VER > 14
 
-// is_callable
+// invoke_result
 
-template <class _Fn, class _Ret = void>
-struct _LIBCPP_TEMPLATE_VIS is_callable;
+template <class _Fn, class... _Args>
+struct _LIBCPP_TEMPLATE_VIS invoke_result
+    : __invoke_of<_Fn, _Args...>
+{
+};
 
-template <class _Fn, class ..._Args, class _Ret>
-struct _LIBCPP_TEMPLATE_VIS is_callable<_Fn(_Args...), _Ret>
+template <class _Fn, class... _Args>
+using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;
+
+// is_invocable
+
+template <class _Fn, class ..._Args>
+struct _LIBCPP_TEMPLATE_VIS is_invocable
+    : integral_constant<bool, __invokable<_Fn, _Args...>::value> {};
+
+template <class _Ret, class _Fn, class ..._Args>
+struct _LIBCPP_TEMPLATE_VIS is_invocable_r
     : integral_constant<bool, __invokable_r<_Ret, _Fn, _Args...>::value> {};
 
-template <class _Fn, class _Ret = void>
-constexpr bool is_callable_v = is_callable<_Fn, _Ret>::value;
+template <class _Fn, class ..._Args>
+constexpr bool is_invocable_v = is_invocable<_Fn, _Args...>::value;
+
+template <class _Ret, class _Fn, class ..._Args>
+constexpr bool is_invocable_r_v = is_invocable_r<_Ret, _Fn, _Args...>::value;
 
 // is_nothrow_callable
 
-template <class _Fn, class _Ret = void>
-struct _LIBCPP_TEMPLATE_VIS is_nothrow_callable;
+template <class _Fn, class ..._Args>
+struct _LIBCPP_TEMPLATE_VIS is_nothrow_invocable
+    : integral_constant<bool, __nothrow_invokable<_Fn, _Args...>::value> {};
 
-template <class _Fn, class ..._Args, class _Ret>
-struct _LIBCPP_TEMPLATE_VIS is_nothrow_callable<_Fn(_Args...), _Ret>
-    : integral_constant<bool, __nothrow_invokable_r<_Ret, _Fn, _Args...>::value>
-{};
+template <class _Ret, class _Fn, class ..._Args>
+struct _LIBCPP_TEMPLATE_VIS is_nothrow_invocable_r
+    : integral_constant<bool, __nothrow_invokable_r<_Ret, _Fn, _Args...>::value> {};
 
-template <class _Fn, class _Ret = void>
-constexpr bool is_nothrow_callable_v = is_nothrow_callable<_Fn, _Ret>::value;
+template <class _Fn, class ..._Args>
+constexpr bool is_nothrow_invocable_v = is_nothrow_invocable<_Fn, _Args...>::value;
+
+template <class _Ret, class _Fn, class ..._Args>
+constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r<_Ret, _Fn, _Args...>::value;
 
 #endif // _LIBCPP_STD_VER > 14
 
diff --git a/include/variant b/include/variant
index 4bb38b72..8a66add 100644
--- a/include/variant
+++ b/include/variant
@@ -582,7 +582,7 @@
 private:
   template <class _Visitor, class... _Values>
   static constexpr void __std_visit_exhaustive_visitor_check() {
-    static_assert(is_callable_v<_Visitor(_Values...)>,
+    static_assert(is_invocable_v<_Visitor, _Values...>,
                   "`std::visit` requires the visitor to be exhaustive.");
   }