[libcxx] r320509 - [libcxx] P0604, invoke_result and is_invocable

Zhihao Yuan via cfe-commits cfe-commits at lists.llvm.org
Tue Dec 12 10:42:04 PST 2017


Author: lichray
Date: Tue Dec 12 10:42:04 2017
New Revision: 320509

URL: http://llvm.org/viewvc/llvm-project?rev=320509&view=rev
Log:
[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

Added:
    libcxx/trunk/test/std/utilities/meta/meta.rel/is_invocable.pass.cpp
    libcxx/trunk/test/std/utilities/meta/meta.rel/is_nothrow_invocable.pass.cpp
Removed:
    libcxx/trunk/test/std/utilities/meta/meta.rel/is_callable.pass.cpp
    libcxx/trunk/test/std/utilities/meta/meta.rel/is_nothrow_callable.pass.cpp
Modified:
    libcxx/trunk/include/type_traits
    libcxx/trunk/include/variant
    libcxx/trunk/test/std/utilities/function.objects/func.not_fn/not_fn.pass.cpp
    libcxx/trunk/test/std/utilities/function.objects/unord.hash/non_enum.pass.cpp
    libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/result_of.pass.cpp
    libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/result_of11.pass.cpp

Modified: libcxx/trunk/include/type_traits
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/type_traits?rev=320509&r1=320508&r2=320509&view=diff
==============================================================================
--- libcxx/trunk/include/type_traits (original)
+++ libcxx/trunk/include/type_traits Tue Dec 12 10:42:04 2017
@@ -137,13 +137,11 @@ namespace std
     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, 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_invocable;
+    template <class R, class Fn, class... ArgTypes> struct is_invocable_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 @@ namespace std
     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 @@ namespace std
       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 @@ namespace std
         = 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 @@ using __nothrow_invokable_r =
     >;
 
 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 @@ template <class _Tp> using result_of_t =
 
 #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>
+using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;
+
+// is_invocable
 
-template <class _Fn, class ..._Args, class _Ret>
-struct _LIBCPP_TEMPLATE_VIS is_callable<_Fn(_Args...), _Ret>
+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 _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 ..._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 _Fn, class ..._Args>
+constexpr bool is_nothrow_invocable_v = is_nothrow_invocable<_Fn, _Args...>::value;
 
-template <class _Fn, class _Ret = void>
-constexpr bool is_nothrow_callable_v = is_nothrow_callable<_Fn, _Ret>::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
 

Modified: libcxx/trunk/include/variant
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/variant?rev=320509&r1=320508&r2=320509&view=diff
==============================================================================
--- libcxx/trunk/include/variant (original)
+++ libcxx/trunk/include/variant Tue Dec 12 10:42:04 2017
@@ -582,7 +582,7 @@ struct __variant {
 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.");
   }
 

Modified: libcxx/trunk/test/std/utilities/function.objects/func.not_fn/not_fn.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/function.objects/func.not_fn/not_fn.pass.cpp?rev=320509&r1=320508&r2=320509&view=diff
==============================================================================
--- libcxx/trunk/test/std/utilities/function.objects/func.not_fn/not_fn.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/function.objects/func.not_fn/not_fn.pass.cpp Tue Dec 12 10:42:04 2017
@@ -438,26 +438,26 @@ void throws_in_constructor_test()
 void call_operator_sfinae_test() {
     { // wrong number of arguments
         using T = decltype(std::not_fn(returns_true));
-        static_assert(std::is_callable<T()>::value, ""); // callable only with no args
-        static_assert(!std::is_callable<T(bool)>::value, "");
+        static_assert(std::is_invocable<T>::value, ""); // callable only with no args
+        static_assert(!std::is_invocable<T, bool>::value, "");
     }
     { // violates const correctness (member function pointer)
         using T = decltype(std::not_fn(&MemFunCallable::return_value_nc));
-        static_assert(std::is_callable<T(MemFunCallable&)>::value, "");
-        static_assert(!std::is_callable<T(const MemFunCallable&)>::value, "");
+        static_assert(std::is_invocable<T, MemFunCallable&>::value, "");
+        static_assert(!std::is_invocable<T, const MemFunCallable&>::value, "");
     }
     { // violates const correctness (call object)
         using Obj = CopyCallable<bool>;
         using NCT = decltype(std::not_fn(Obj{true}));
         using CT = const NCT;
-        static_assert(std::is_callable<NCT()>::value, "");
-        static_assert(!std::is_callable<CT()>::value, "");
+        static_assert(std::is_invocable<NCT>::value, "");
+        static_assert(!std::is_invocable<CT>::value, "");
     }
     { // returns bad type with no operator!
         auto fn = [](auto x) { return x; };
         using T = decltype(std::not_fn(fn));
-        static_assert(std::is_callable<T(bool)>::value, "");
-        static_assert(!std::is_callable<T(std::string)>::value, "");
+        static_assert(std::is_invocable<T, bool>::value, "");
+        static_assert(!std::is_invocable<T, std::string>::value, "");
     }
 }
 

Modified: libcxx/trunk/test/std/utilities/function.objects/unord.hash/non_enum.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/function.objects/unord.hash/non_enum.pass.cpp?rev=320509&r1=320508&r2=320509&view=diff
==============================================================================
--- libcxx/trunk/test/std/utilities/function.objects/unord.hash/non_enum.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/function.objects/unord.hash/non_enum.pass.cpp Tue Dec 12 10:42:04 2017
@@ -32,7 +32,7 @@ int main()
     static_assert(!std::is_copy_assignable<H>::value, "");
     static_assert(!std::is_move_assignable<H>::value, "");
 #if TEST_STD_VER > 14
-    static_assert(!std::is_callable<H(X&)>::value, "");
-    static_assert(!std::is_callable<H(X const&)>::value, "");
+    static_assert(!std::is_invocable<H, X&>::value, "");
+    static_assert(!std::is_invocable<H, X const&>::value, "");
 #endif
 }

Removed: libcxx/trunk/test/std/utilities/meta/meta.rel/is_callable.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/meta/meta.rel/is_callable.pass.cpp?rev=320508&view=auto
==============================================================================
--- libcxx/trunk/test/std/utilities/meta/meta.rel/is_callable.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/meta/meta.rel/is_callable.pass.cpp (removed)
@@ -1,160 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++98, c++03, c++11, c++14
-
-// type_traits
-
-// is_callable
-
-// Most testing of is_callable is done within the [meta.trans.other] result_of
-// tests.
-
-#include <type_traits>
-#include <functional>
-#include <memory>
-
-#include "test_macros.h"
-
-struct Tag {};
-struct DerFromTag : Tag {};
-
-struct Implicit {
-  Implicit(int) {}
-};
-
-struct Explicit {
-  explicit Explicit(int) {}
-};
-
-struct NotCallableWithInt {
-  int operator()(int) = delete;
-  int operator()(Tag) { return 42; }
-};
-
-int main()
-{
-    {
-        using Fn = int(Tag::*)(int);
-        using RFn = int(Tag::*)(int) &&;
-        // INVOKE bullet 1, 2 and 3
-        {
-            // Bullet 1
-            static_assert(std::is_callable<Fn(Tag&, int)>::value, "");
-            static_assert(std::is_callable<Fn(DerFromTag&, int)>::value, "");
-            static_assert(std::is_callable<RFn(Tag&&, int)>::value, "");
-            static_assert(!std::is_callable<RFn(Tag&, int)>::value, "");
-            static_assert(!std::is_callable<Fn(Tag&)>::value, "");
-            static_assert(!std::is_callable<Fn(Tag const&, int)>::value, "");
-        }
-        {
-            // Bullet 2
-            using T = std::reference_wrapper<Tag>;
-            using DT = std::reference_wrapper<DerFromTag>;
-            using CT = std::reference_wrapper<const Tag>;
-            static_assert(std::is_callable<Fn(T&, int)>::value, "");
-            static_assert(std::is_callable<Fn(DT&, int)>::value, "");
-            static_assert(std::is_callable<Fn(const T&, int)>::value, "");
-            static_assert(std::is_callable<Fn(T&&, int)>::value, "");
-            static_assert(!std::is_callable<Fn(CT&, int)>::value, "");
-            static_assert(!std::is_callable<RFn(T, int)>::value, "");
-        }
-        {
-            // Bullet 3
-            using T = Tag*;
-            using DT = DerFromTag*;
-            using CT = const Tag*;
-            using ST = std::unique_ptr<Tag>;
-            static_assert(std::is_callable<Fn(T&, int)>::value, "");
-            static_assert(std::is_callable<Fn(DT&, int)>::value, "");
-            static_assert(std::is_callable<Fn(const T&, int)>::value, "");
-            static_assert(std::is_callable<Fn(T&&, int)>::value, "");
-            static_assert(std::is_callable<Fn(ST, int)>::value, "");
-            static_assert(!std::is_callable<Fn(CT&, int)>::value, "");
-            static_assert(!std::is_callable<RFn(T, int)>::value, "");
-        }
-    }
-    {
-        // Bullets 4, 5 and 6
-        using Fn = int (Tag::*);
-        static_assert(!std::is_callable<Fn()>::value, "");
-        {
-            // Bullet 4
-            static_assert(std::is_callable<Fn(Tag&)>::value, "");
-            static_assert(std::is_callable<Fn(DerFromTag&)>::value, "");
-            static_assert(std::is_callable<Fn(Tag&&)>::value, "");
-            static_assert(std::is_callable<Fn(Tag const&)>::value, "");
-        }
-        {
-            // Bullet 5
-            using T = std::reference_wrapper<Tag>;
-            using DT = std::reference_wrapper<DerFromTag>;
-            using CT = std::reference_wrapper<const Tag>;
-            static_assert(std::is_callable<Fn(T&)>::value, "");
-            static_assert(std::is_callable<Fn(DT&)>::value, "");
-            static_assert(std::is_callable<Fn(const T&)>::value, "");
-            static_assert(std::is_callable<Fn(T&&)>::value, "");
-            static_assert(std::is_callable<Fn(CT&)>::value, "");
-        }
-        {
-            // Bullet 6
-            using T = Tag*;
-            using DT = DerFromTag*;
-            using CT = const Tag*;
-            using ST = std::unique_ptr<Tag>;
-            static_assert(std::is_callable<Fn(T&)>::value, "");
-            static_assert(std::is_callable<Fn(DT&)>::value, "");
-            static_assert(std::is_callable<Fn(const T&)>::value, "");
-            static_assert(std::is_callable<Fn(T&&)>::value, "");
-            static_assert(std::is_callable<Fn(ST)>::value, "");
-            static_assert(std::is_callable<Fn(CT&)>::value, "");
-        }
-    }
-    {
-        // INVOKE bullet 7
-        {
-            // Function pointer
-            using Fp = void(*)(Tag&, int);
-            static_assert(std::is_callable<Fp(Tag&, int)>::value, "");
-            static_assert(std::is_callable<Fp(DerFromTag&, int)>::value, "");
-            static_assert(!std::is_callable<Fp(const Tag&, int)>::value, "");
-            static_assert(!std::is_callable<Fp()>::value, "");
-            static_assert(!std::is_callable<Fp(Tag&)>::value, "");
-        }
-        {
-            // Function reference
-            using Fp = void(&)(Tag&, int);
-            static_assert(std::is_callable<Fp(Tag&, int)>::value, "");
-            static_assert(std::is_callable<Fp(DerFromTag&, int)>::value, "");
-            static_assert(!std::is_callable<Fp(const Tag&, int)>::value, "");
-            static_assert(!std::is_callable<Fp()>::value, "");
-            static_assert(!std::is_callable<Fp(Tag&)>::value, "");
-        }
-        {
-            // Function object
-            using Fn = NotCallableWithInt;
-            static_assert(std::is_callable<Fn(Tag)>::value, "");
-            static_assert(!std::is_callable<Fn(int)>::value, "");
-        }
-    }
-    {
-        // Check that the conversion to the return type is properly checked
-        using Fn = int(*)();
-        static_assert(std::is_callable<Fn(), Implicit>::value, "");
-        static_assert(std::is_callable<Fn(), double>::value, "");
-        static_assert(std::is_callable<Fn(), const volatile void>::value, "");
-        static_assert(!std::is_callable<Fn(), Explicit>::value, "");
-    }
-    {
-        // Check for is_callable_v
-        using Fn = void(*)();
-        static_assert(std::is_callable_v<Fn()>, "");
-        static_assert(!std::is_callable_v<Fn(int)>, "");
-    }
-}

Added: libcxx/trunk/test/std/utilities/meta/meta.rel/is_invocable.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/meta/meta.rel/is_invocable.pass.cpp?rev=320509&view=auto
==============================================================================
--- libcxx/trunk/test/std/utilities/meta/meta.rel/is_invocable.pass.cpp (added)
+++ libcxx/trunk/test/std/utilities/meta/meta.rel/is_invocable.pass.cpp Tue Dec 12 10:42:04 2017
@@ -0,0 +1,166 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+
+// type_traits
+
+// is_invocable
+
+// Most testing of is_invocable is done within the [meta.trans.other] result_of
+// tests.
+
+#include <type_traits>
+#include <functional>
+#include <memory>
+
+#include "test_macros.h"
+
+struct Tag {};
+struct DerFromTag : Tag {};
+
+struct Implicit {
+  Implicit(int) {}
+};
+
+struct Explicit {
+  explicit Explicit(int) {}
+};
+
+struct NotCallableWithInt {
+  int operator()(int) = delete;
+  int operator()(Tag) { return 42; }
+};
+
+int main()
+{
+    {
+        using Fn = int(Tag::*)(int);
+        using RFn = int(Tag::*)(int) &&;
+        // INVOKE bullet 1, 2 and 3
+        {
+            // Bullet 1
+            static_assert(std::is_invocable<Fn, Tag&, int>::value, "");
+            static_assert(std::is_invocable<Fn, DerFromTag&, int>::value, "");
+            static_assert(std::is_invocable<RFn, Tag&&, int>::value, "");
+            static_assert(!std::is_invocable<RFn, Tag&, int>::value, "");
+            static_assert(!std::is_invocable<Fn, Tag&>::value, "");
+            static_assert(!std::is_invocable<Fn, Tag const&, int>::value, "");
+        }
+        {
+            // Bullet 2
+            using T = std::reference_wrapper<Tag>;
+            using DT = std::reference_wrapper<DerFromTag>;
+            using CT = std::reference_wrapper<const Tag>;
+            static_assert(std::is_invocable<Fn, T&, int>::value, "");
+            static_assert(std::is_invocable<Fn, DT&, int>::value, "");
+            static_assert(std::is_invocable<Fn, const T&, int>::value, "");
+            static_assert(std::is_invocable<Fn, T&&, int>::value, "");
+            static_assert(!std::is_invocable<Fn, CT&, int>::value, "");
+            static_assert(!std::is_invocable<RFn, T, int>::value, "");
+        }
+        {
+            // Bullet 3
+            using T = Tag*;
+            using DT = DerFromTag*;
+            using CT = const Tag*;
+            using ST = std::unique_ptr<Tag>;
+            static_assert(std::is_invocable<Fn, T&, int>::value, "");
+            static_assert(std::is_invocable<Fn, DT&, int>::value, "");
+            static_assert(std::is_invocable<Fn, const T&, int>::value, "");
+            static_assert(std::is_invocable<Fn, T&&, int>::value, "");
+            static_assert(std::is_invocable<Fn, ST, int>::value, "");
+            static_assert(!std::is_invocable<Fn, CT&, int>::value, "");
+            static_assert(!std::is_invocable<RFn, T, int>::value, "");
+        }
+    }
+    {
+        // Bullets 4, 5 and 6
+        using Fn = int (Tag::*);
+        static_assert(!std::is_invocable<Fn>::value, "");
+        {
+            // Bullet 4
+            static_assert(std::is_invocable<Fn, Tag&>::value, "");
+            static_assert(std::is_invocable<Fn, DerFromTag&>::value, "");
+            static_assert(std::is_invocable<Fn, Tag&&>::value, "");
+            static_assert(std::is_invocable<Fn, Tag const&>::value, "");
+        }
+        {
+            // Bullet 5
+            using T = std::reference_wrapper<Tag>;
+            using DT = std::reference_wrapper<DerFromTag>;
+            using CT = std::reference_wrapper<const Tag>;
+            static_assert(std::is_invocable<Fn, T&>::value, "");
+            static_assert(std::is_invocable<Fn, DT&>::value, "");
+            static_assert(std::is_invocable<Fn, const T&>::value, "");
+            static_assert(std::is_invocable<Fn, T&&>::value, "");
+            static_assert(std::is_invocable<Fn, CT&>::value, "");
+        }
+        {
+            // Bullet 6
+            using T = Tag*;
+            using DT = DerFromTag*;
+            using CT = const Tag*;
+            using ST = std::unique_ptr<Tag>;
+            static_assert(std::is_invocable<Fn, T&>::value, "");
+            static_assert(std::is_invocable<Fn, DT&>::value, "");
+            static_assert(std::is_invocable<Fn, const T&>::value, "");
+            static_assert(std::is_invocable<Fn, T&&>::value, "");
+            static_assert(std::is_invocable<Fn, ST>::value, "");
+            static_assert(std::is_invocable<Fn, CT&>::value, "");
+        }
+    }
+    {
+        // INVOKE bullet 7
+        {
+            // Function pointer
+            using Fp = void(*)(Tag&, int);
+            static_assert(std::is_invocable<Fp, Tag&, int>::value, "");
+            static_assert(std::is_invocable<Fp, DerFromTag&, int>::value, "");
+            static_assert(!std::is_invocable<Fp, const Tag&, int>::value, "");
+            static_assert(!std::is_invocable<Fp>::value, "");
+            static_assert(!std::is_invocable<Fp, Tag&>::value, "");
+        }
+        {
+            // Function reference
+            using Fp = void(&)(Tag&, int);
+            static_assert(std::is_invocable<Fp, Tag&, int>::value, "");
+            static_assert(std::is_invocable<Fp, DerFromTag&, int>::value, "");
+            static_assert(!std::is_invocable<Fp, const Tag&, int>::value, "");
+            static_assert(!std::is_invocable<Fp>::value, "");
+            static_assert(!std::is_invocable<Fp, Tag&>::value, "");
+        }
+        {
+            // Function object
+            using Fn = NotCallableWithInt;
+            static_assert(std::is_invocable<Fn, Tag>::value, "");
+            static_assert(!std::is_invocable<Fn, int>::value, "");
+        }
+    }
+    {
+        // Check that the conversion to the return type is properly checked
+        using Fn = int(*)();
+        static_assert(std::is_invocable_r<Implicit, Fn>::value, "");
+        static_assert(std::is_invocable_r<double, Fn>::value, "");
+        static_assert(std::is_invocable_r<const volatile void, Fn>::value, "");
+        static_assert(!std::is_invocable_r<Explicit, Fn>::value, "");
+    }
+    {
+        // Check for is_invocable_v
+        using Fn = void(*)();
+        static_assert(std::is_invocable_v<Fn>, "");
+        static_assert(!std::is_invocable_v<Fn, int>, "");
+    }
+    {
+        // Check for is_invocable_r_v
+        using Fn = void(*)();
+        static_assert(std::is_invocable_r_v<void, Fn>, "");
+        static_assert(!std::is_invocable_r_v<int, Fn>, "");
+    }
+}

Removed: libcxx/trunk/test/std/utilities/meta/meta.rel/is_nothrow_callable.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/meta/meta.rel/is_nothrow_callable.pass.cpp?rev=320508&view=auto
==============================================================================
--- libcxx/trunk/test/std/utilities/meta/meta.rel/is_nothrow_callable.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/meta/meta.rel/is_nothrow_callable.pass.cpp (removed)
@@ -1,115 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++98, c++03, c++11, c++14
-
-// type_traits
-
-// is_nothrow_callable
-
-#include <type_traits>
-#include <functional>
-
-#include "test_macros.h"
-
-struct Tag {};
-
-struct Implicit {
-  Implicit(int) noexcept {}
-};
-
-struct ThrowsImplicit {
-  ThrowsImplicit(int) {}
-};
-
-struct Explicit {
-  explicit Explicit(int) noexcept {}
-};
-
-template <bool IsNoexcept, class Ret, class ...Args>
-struct CallObject {
-  Ret operator()(Args&&...) const noexcept(IsNoexcept);
-};
-
-template <class Fn>
-constexpr bool throws_callable() {
-    return std::is_callable<Fn>::value &&
-        !std::is_nothrow_callable<Fn>::value;
-}
-
-template <class Fn, class Ret>
-constexpr bool throws_callable() {
-    return std::is_callable<Fn, Ret>::value &&
-        !std::is_nothrow_callable<Fn, Ret>::value;
-}
-
-// FIXME(EricWF) Don't test the where noexcept is *not* part of the type system
-// once implementations have caught up.
-void test_noexcept_function_pointers()
-{
-    struct Dummy { void foo() noexcept {} static void bar() noexcept {} };
-#if !defined(__cpp_noexcept_function_type)
-    {
-        // Check that PMF's and function pointers *work*. is_nothrow_callable will always
-        // return false because 'noexcept' is not part of the function type.
-        static_assert(throws_callable<decltype(&Dummy::foo)(Dummy&)>(), "");
-        static_assert(throws_callable<decltype(&Dummy::bar)()>(), "");
-    }
-#else
-    {
-        // Check that PMF's and function pointers actually work and that
-        // is_nothrow_callable returns true for noexcept PMF's and function
-        // pointers.
-        static_assert(std::is_nothrow_callable<decltype(&Dummy::foo)(Dummy&)>::value, "");
-        static_assert(std::is_nothrow_callable<decltype(&Dummy::bar)()>::value, "");
-    }
-#endif
-}
-
-int main()
-{
-    {
-        // Check that the conversion to the return type is properly checked
-        using Fn = CallObject<true, int>;
-        static_assert(std::is_nothrow_callable<Fn(), Implicit>::value, "");
-        static_assert(std::is_nothrow_callable<Fn(), double>::value, "");
-        static_assert(std::is_nothrow_callable<Fn(), const volatile void>::value, "");
-        static_assert(throws_callable<Fn(), ThrowsImplicit>(), "");
-        static_assert(!std::is_nothrow_callable<Fn(), Explicit>(), "");
-    }
-    {
-        // Check that the conversion to the parameters is properly checked
-        using Fn = CallObject<true, void, const Implicit&, const ThrowsImplicit&>;
-        static_assert(std::is_nothrow_callable<Fn(Implicit&, ThrowsImplicit&)>::value, "");
-        static_assert(std::is_nothrow_callable<Fn(int, ThrowsImplicit&)>::value, "");
-        static_assert(throws_callable<Fn(int, int)>(), "");
-        static_assert(!std::is_nothrow_callable<Fn()>::value, "");
-    }
-    {
-        // Check that the noexcept-ness of function objects is checked.
-        using Fn = CallObject<true, void>;
-        using Fn2 = CallObject<false, void>;
-        static_assert(std::is_nothrow_callable<Fn()>::value, "");
-        static_assert(throws_callable<Fn2()>(), "");
-    }
-    {
-        // Check that PMD derefs are noexcept
-        using Fn = int (Tag::*);
-        static_assert(std::is_nothrow_callable<Fn(Tag&)>::value, "");
-        static_assert(std::is_nothrow_callable<Fn(Tag&), Implicit>::value, "");
-        static_assert(throws_callable<Fn(Tag&), ThrowsImplicit>(), "");
-    }
-    {
-        // Check for is_nothrow_callable_v
-        using Fn = CallObject<true, int>;
-        static_assert(std::is_nothrow_callable_v<Fn()>, "");
-        static_assert(!std::is_nothrow_callable_v<Fn(int)>, "");
-    }
-    test_noexcept_function_pointers();
-}

Added: libcxx/trunk/test/std/utilities/meta/meta.rel/is_nothrow_invocable.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/meta/meta.rel/is_nothrow_invocable.pass.cpp?rev=320509&view=auto
==============================================================================
--- libcxx/trunk/test/std/utilities/meta/meta.rel/is_nothrow_invocable.pass.cpp (added)
+++ libcxx/trunk/test/std/utilities/meta/meta.rel/is_nothrow_invocable.pass.cpp Tue Dec 12 10:42:04 2017
@@ -0,0 +1,121 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+
+// type_traits
+
+// is_nothrow_invocable
+
+#include <type_traits>
+#include <functional>
+
+#include "test_macros.h"
+
+struct Tag {};
+
+struct Implicit {
+  Implicit(int) noexcept {}
+};
+
+struct ThrowsImplicit {
+  ThrowsImplicit(int) {}
+};
+
+struct Explicit {
+  explicit Explicit(int) noexcept {}
+};
+
+template <bool IsNoexcept, class Ret, class ...Args>
+struct CallObject {
+  Ret operator()(Args&&...) const noexcept(IsNoexcept);
+};
+
+template <class Fn, class ...Args>
+constexpr bool throws_invocable() {
+    return std::is_invocable<Fn, Args...>::value &&
+        !std::is_nothrow_invocable<Fn, Args...>::value;
+}
+
+template <class Ret, class Fn, class ...Args>
+constexpr bool throws_invocable_r() {
+    return std::is_invocable_r<Ret, Fn, Args...>::value &&
+        !std::is_nothrow_invocable_r<Ret, Fn, Args...>::value;
+}
+
+// FIXME(EricWF) Don't test the where noexcept is *not* part of the type system
+// once implementations have caught up.
+void test_noexcept_function_pointers()
+{
+    struct Dummy { void foo() noexcept {} static void bar() noexcept {} };
+#if !defined(__cpp_noexcept_function_type)
+    {
+        // Check that PMF's and function pointers *work*. is_nothrow_invocable will always
+        // return false because 'noexcept' is not part of the function type.
+        static_assert(throws_invocable<decltype(&Dummy::foo), Dummy&>(), "");
+        static_assert(throws_invocable<decltype(&Dummy::bar)>(), "");
+    }
+#else
+    {
+        // Check that PMF's and function pointers actually work and that
+        // is_nothrow_invocable returns true for noexcept PMF's and function
+        // pointers.
+        static_assert(std::is_nothrow_invocable<decltype(&Dummy::foo), Dummy&>::value, "");
+        static_assert(std::is_nothrow_invocable<decltype(&Dummy::bar)>::value, "");
+    }
+#endif
+}
+
+int main()
+{
+    {
+        // Check that the conversion to the return type is properly checked
+        using Fn = CallObject<true, int>;
+        static_assert(std::is_nothrow_invocable_r<Implicit, Fn>::value, "");
+        static_assert(std::is_nothrow_invocable_r<double, Fn>::value, "");
+        static_assert(std::is_nothrow_invocable_r<const volatile void, Fn>::value, "");
+        static_assert(throws_invocable_r<ThrowsImplicit, Fn>(), "");
+        static_assert(!std::is_nothrow_invocable<Fn(), Explicit>(), "");
+    }
+    {
+        // Check that the conversion to the parameters is properly checked
+        using Fn = CallObject<true, void, const Implicit&, const ThrowsImplicit&>;
+        static_assert(std::is_nothrow_invocable<Fn, Implicit&, ThrowsImplicit&>::value, "");
+        static_assert(std::is_nothrow_invocable<Fn, int, ThrowsImplicit&>::value, "");
+        static_assert(throws_invocable<Fn, int, int>(), "");
+        static_assert(!std::is_nothrow_invocable<Fn>::value, "");
+    }
+    {
+        // Check that the noexcept-ness of function objects is checked.
+        using Fn = CallObject<true, void>;
+        using Fn2 = CallObject<false, void>;
+        static_assert(std::is_nothrow_invocable<Fn>::value, "");
+        static_assert(throws_invocable<Fn2>(), "");
+    }
+    {
+        // Check that PMD derefs are noexcept
+        using Fn = int (Tag::*);
+        static_assert(std::is_nothrow_invocable<Fn, Tag&>::value, "");
+        static_assert(std::is_nothrow_invocable_r<Implicit, Fn, Tag&>::value, "");
+        static_assert(throws_invocable_r<ThrowsImplicit, Fn, Tag&>(), "");
+    }
+    {
+        // Check for is_nothrow_invocable_v
+        using Fn = CallObject<true, int>;
+        static_assert(std::is_nothrow_invocable_v<Fn>, "");
+        static_assert(!std::is_nothrow_invocable_v<Fn, int>, "");
+    }
+    {
+        // Check for is_nothrow_invocable_r_v
+        using Fn = CallObject<true, int>;
+        static_assert(std::is_nothrow_invocable_r_v<void, Fn>, "");
+        static_assert(!std::is_nothrow_invocable_r_v<int, Fn, int>, "");
+    }
+    test_noexcept_function_pointers();
+}

Modified: libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/result_of.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/result_of.pass.cpp?rev=320509&r1=320508&r2=320509&view=diff
==============================================================================
--- libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/result_of.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/result_of.pass.cpp Tue Dec 12 10:42:04 2017
@@ -42,16 +42,46 @@ struct HasType : std::false_type {};
 template <class T>
 struct HasType<T, typename Voider<typename T::type>::type> : std::true_type {};
 
+#if TEST_STD_VER > 14
+template <typename T, typename U>
+struct test_invoke_result;
+
+template <typename Fn, typename ...Args, typename Ret>
+struct test_invoke_result<Fn(Args...), Ret>
+{
+    static void call()
+    {
+        static_assert(std::is_invocable<Fn, Args...>::value, "");
+        static_assert(std::is_invocable_r<Ret, Fn, Args...>::value, "");
+        static_assert((std::is_same<typename std::invoke_result<Fn, Args...>::type, Ret>::value), "");
+    }
+};
+#endif
+
 template <class T, class U>
 void test_result_of()
 {
+    static_assert((std::is_same<typename std::result_of<T>::type, U>::value), "");
 #if TEST_STD_VER > 14
-    static_assert(std::is_callable<T>::value, "");
-    static_assert(std::is_callable<T, U>::value, "");
+    test_invoke_result<T, U>::call();
 #endif
-    static_assert((std::is_same<typename std::result_of<T>::type, U>::value), "");
 }
 
+#if TEST_STD_VER > 14
+template <typename T>
+struct test_invoke_no_result;
+
+template <typename Fn, typename ...Args>
+struct test_invoke_no_result<Fn(Args...)>
+{
+    static void call()
+    {
+        static_assert(std::is_invocable<Fn, Args...>::value == false, "");
+        static_assert((!HasType<std::invoke_result<Fn, Args...> >::value), "");
+    }
+};
+#endif
+
 template <class T>
 void test_no_result()
 {
@@ -59,7 +89,7 @@ void test_no_result()
     static_assert((!HasType<std::result_of<T> >::value), "");
 #endif
 #if TEST_STD_VER > 14
-    static_assert(std::is_callable<T>::value == false, "");
+    test_invoke_no_result<T>::call();
 #endif
 }
 

Modified: libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/result_of11.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/result_of11.pass.cpp?rev=320509&r1=320508&r2=320509&view=diff
==============================================================================
--- libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/result_of11.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/result_of11.pass.cpp Tue Dec 12 10:42:04 2017
@@ -27,6 +27,23 @@ struct wat
 struct F {};
 struct FD : public F {};
 
+#if TEST_STD_VER > 14
+template <typename T, typename U>
+struct test_invoke_result;
+
+template <typename Fn, typename ...Args, typename Ret>
+struct test_invoke_result<Fn(Args...), Ret>
+{
+    static void call()
+    {
+        static_assert(std::is_invocable<Fn, Args...>::value, "");
+        static_assert(std::is_invocable_r<Ret, Fn, Args...>::value, "");
+        static_assert((std::is_same<typename std::invoke_result<Fn, Args...>::type, Ret>::value), "");
+        static_assert((std::is_same<std::invoke_result_t<Fn, Args...>, Ret>::value), "");
+    }
+};
+#endif
+
 template <class T, class U>
 void test_result_of_imp()
 {
@@ -35,8 +52,7 @@ void test_result_of_imp()
     static_assert((std::is_same<std::result_of_t<T>, U>::value), "");
 #endif
 #if TEST_STD_VER > 14
-    static_assert(std::is_callable<T>::value, "");
-    static_assert(std::is_callable<T, U>::value, "");
+    test_invoke_result<T, U>::call();
 #endif
 }
 




More information about the cfe-commits mailing list