Commit 88742563 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Backport invocability variable templates

Summary: [Folly] Backport invocability variable templates: `is_invocable_v`, `is_invocable_r_v`, `is_nothrow_invocable_v`, `is_nothrow_invocable_r_v`. And for the member-invoke and free-invoke traits.

Reviewed By: ericniebler

Differential Revision: D17950331

fbshipit-source-id: 5409d7a72116b0976573e1f64760c5ef9274966f
parent d9b854ef
......@@ -19,6 +19,7 @@
#include <functional>
#include <type_traits>
#include <folly/Portability.h>
#include <folly/Preprocessor.h>
#include <folly/Traits.h>
......@@ -28,9 +29,13 @@
* * std::invoke_result
* * std::invoke_result_t
* * std::is_invocable
* * std::is_invocable_v
* * std::is_invocable_r
* * std::is_invocable_r_v
* * std::is_nothrow_invocable
* * std::is_nothrow_invocable_v
* * std::is_nothrow_invocable_r
* * std::is_nothrow_invocable_r_v
*/
#if __cpp_lib_invoke >= 201411 || _MSC_VER
......@@ -71,8 +76,12 @@ namespace folly {
/* using override */ using std::invoke_result_t;
/* using override */ using std::is_invocable;
/* using override */ using std::is_invocable_r;
/* using override */ using std::is_invocable_r_v;
/* using override */ using std::is_invocable_v;
/* using override */ using std::is_nothrow_invocable;
/* using override */ using std::is_nothrow_invocable_r;
/* using override */ using std::is_nothrow_invocable_r_v;
/* using override */ using std::is_nothrow_invocable_v;
} // namespace folly
......@@ -145,20 +154,40 @@ using invoke_result_t = typename invoke_result<F, Args...>::type;
template <typename F, typename... Args>
struct is_invocable : invoke_detail::is_invocable<void, F, Args...> {};
// mimic: std::is_invocable_v, C++17
template <typename F, typename... Args>
FOLLY_INLINE_VARIABLE constexpr bool is_invocable_v =
is_invocable<F, Args...>::value;
// mimic: std::is_invocable_r, C++17
template <typename R, typename F, typename... Args>
struct is_invocable_r : invoke_detail::is_invocable_r<void, R, F, Args...> {};
// mimic: std::is_invocable_r_v, C++17
template <typename R, typename F, typename... Args>
FOLLY_INLINE_VARIABLE constexpr bool is_invocable_r_v =
is_invocable_r<R, F, Args...>::value;
// mimic: std::is_nothrow_invocable, C++17
template <typename F, typename... Args>
struct is_nothrow_invocable
: invoke_detail::is_nothrow_invocable<void, F, Args...> {};
// mimic: std::is_nothrow_invocable_v, C++17
template <typename F, typename... Args>
FOLLY_INLINE_VARIABLE constexpr bool is_nothrow_invocable_v =
is_nothrow_invocable<F, Args...>::value;
// mimic: std::is_nothrow_invocable_r, C++17
template <typename R, typename F, typename... Args>
struct is_nothrow_invocable_r
: invoke_detail::is_nothrow_invocable_r<void, R, F, Args...> {};
// mimic: std::is_nothrow_invocable_r_v, C++17
template <typename R, typename F, typename... Args>
FOLLY_INLINE_VARIABLE constexpr bool is_nothrow_invocable_r_v =
is_nothrow_invocable_r<R, F, Args...>::value;
} // namespace folly
#endif
......@@ -177,13 +206,25 @@ struct free_invoke_proxy {
using invoke_result_t = folly::invoke_result_t<Invoke, Args...>;
template <typename... Args>
struct is_invocable : folly::is_invocable<Invoke, Args...> {};
template <typename... Args>
FOLLY_INLINE_VARIABLE static constexpr bool is_invocable_v =
is_invocable<Args...>::value;
template <typename R, typename... Args>
struct is_invocable_r : folly::is_invocable_r<R, Invoke, Args...> {};
template <typename R, typename... Args>
FOLLY_INLINE_VARIABLE static constexpr bool is_invocable_r_v =
is_invocable_r<R, Args...>::value;
template <typename... Args>
struct is_nothrow_invocable : folly::is_nothrow_invocable<Invoke, Args...> {};
template <typename... Args>
FOLLY_INLINE_VARIABLE static constexpr bool is_nothrow_invocable_v =
is_nothrow_invocable<Args...>::value;
template <typename R, typename... Args>
struct is_nothrow_invocable_r
: folly::is_nothrow_invocable_r<R, Invoke, Args...> {};
template <typename R, typename... Args>
FOLLY_INLINE_VARIABLE static constexpr bool is_nothrow_invocable_r_v =
is_nothrow_invocable_r<R, Args...>::value;
template <typename... Args>
static constexpr auto invoke(Args&&... args) noexcept(
......@@ -207,9 +248,13 @@ struct free_invoke_proxy {
* * invoke_result
* * invoke_result_t
* * is_invocable
* * is_invocable_v
* * is_invocable_r
* * is_invocable_r_v
* * is_nothrow_invocable
* * is_nothrow_invocable_v
* * is_nothrow_invocable_r
* * is_nothrow_invocable_r_v
*
* The container also has a static member function:
*
......@@ -246,19 +291,19 @@ struct free_invoke_proxy {
* traits::invoke_result<Deep::CanFoo, Bar&&> // empty
* traits::invoke_result_t<Deep::CanFoo, Bar&&> // error
*
* traits::is_invocable<CanFoo, Bar&>::value // true
* traits::is_invocable<CanFoo, Bar&&>::value // false
* traits::is_invocable_v<CanFoo, Bar&> // true
* traits::is_invocable_v<CanFoo, Bar&&> // false
*
* traits::is_invocable_r<int, CanFoo, Bar&>::value // true
* traits::is_invocable_r<char*, CanFoo, Bar&>::value // false
* traits::is_invocable_r_v<int, CanFoo, Bar&> // true
* traits::is_invocable_r_v<char*, CanFoo, Bar&> // false
*
* traits::is_nothrow_invocable<CanFoo, Bar&>::value // false
* traits::is_nothrow_invocable<CanFoo, Car&&>::value // true
* traits::is_nothrow_invocable_v<CanFoo, Bar&> // false
* traits::is_nothrow_invocable_v<CanFoo, Car&&> // true
*
* traits::is_nothrow_invocable<int, CanFoo, Bar&>::value // false
* traits::is_nothrow_invocable<char*, CanFoo, Bar&>::value // false
* traits::is_nothrow_invocable<int, CanFoo, Car&&>::value // true
* traits::is_nothrow_invocable<char*, CanFoo, Car&&>::value // false
* traits::is_nothrow_invocable_v<int, CanFoo, Bar&> // false
* traits::is_nothrow_invocable_v<char*, CanFoo, Bar&> // false
* traits::is_nothrow_invocable_v<int, CanFoo, Car&&> // true
* traits::is_nothrow_invocable_v<char*, CanFoo, Car&&> // false
*
* When a name has a primary definition in a fixed namespace and alternate
* definitions in the namespaces of its arguments, the primary definition may
......@@ -316,14 +361,26 @@ struct member_invoke_proxy {
using invoke_result_t = folly::invoke_result_t<Invoke, O, Args...>;
template <typename O, typename... Args>
struct is_invocable : folly::is_invocable<Invoke, O, Args...> {};
template <typename O, typename... Args>
FOLLY_INLINE_VARIABLE static constexpr bool is_invocable_v =
is_invocable<O, Args...>::value;
template <typename R, typename O, typename... Args>
struct is_invocable_r : folly::is_invocable_r<R, Invoke, O, Args...> {};
template <typename R, typename O, typename... Args>
FOLLY_INLINE_VARIABLE static constexpr bool is_invocable_r_v =
is_invocable_r<R, O, Args...>::value;
template <typename O, typename... Args>
struct is_nothrow_invocable
: folly::is_nothrow_invocable<Invoke, O, Args...> {};
template <typename O, typename... Args>
FOLLY_INLINE_VARIABLE static constexpr bool is_nothrow_invocable_v =
is_nothrow_invocable<O, Args...>::value;
template <typename R, typename O, typename... Args>
struct is_nothrow_invocable_r
: folly::is_nothrow_invocable_r<R, Invoke, O, Args...> {};
template <typename R, typename O, typename... Args>
FOLLY_INLINE_VARIABLE static constexpr bool is_nothrow_invocable_r_v =
is_nothrow_invocable_r<R, O, Args...>::value;
template <typename O, typename... Args>
static constexpr auto invoke(O&& o, Args&&... args) noexcept(
......@@ -347,9 +404,13 @@ struct member_invoke_proxy {
* * invoke_result
* * invoke_result_t
* * is_invocable
* * is_invocable_v
* * is_invocable_r
* * is_invocable_r_v
* * is_nothrow_invocable
* * is_nothrow_invocable_v
* * is_nothrow_invocable_r
* * is_nothrow_invocable_r_v
*
* The container also has a static member function:
*
......@@ -385,19 +446,19 @@ struct member_invoke_proxy {
* traits::invoke_result<CanFoo, Bar&&> // empty
* traits::invoke_result_t<CanFoo, Bar&&> // error
*
* traits::is_invocable<CanFoo, Bar&>::value // true
* traits::is_invocable<CanFoo, Bar&&>::value // false
* traits::is_invocable_v<CanFoo, Bar&> // true
* traits::is_invocable_v<CanFoo, Bar&&> // false
*
* traits::is_invocable_r<int, CanFoo, Bar&>::value // true
* traits::is_invocable_r<char*, CanFoo, Bar&>::value // false
* traits::is_invocable_r_v<int, CanFoo, Bar&> // true
* traits::is_invocable_r_v<char*, CanFoo, Bar&> // false
*
* traits::is_nothrow_invocable<CanFoo, Bar&>::value // false
* traits::is_nothrow_invocable<CanFoo, Car&&>::value // true
* traits::is_nothrow_invocable_v<CanFoo, Bar&> // false
* traits::is_nothrow_invocable_v<CanFoo, Car&&> // true
*
* traits::is_nothrow_invocable<int, CanFoo, Bar&>::value // false
* traits::is_nothrow_invocable<char*, CanFoo, Bar&>::value // false
* traits::is_nothrow_invocable<int, CanFoo, Car&&>::value // true
* traits::is_nothrow_invocable<char*, CanFoo, Car&&>::value // false
* traits::is_nothrow_invocable_v<int, CanFoo, Bar&> // false
* traits::is_nothrow_invocable_v<char*, CanFoo, Bar&> // false
* traits::is_nothrow_invocable_v<int, CanFoo, Car&&> // true
* traits::is_nothrow_invocable_v<char*, CanFoo, Car&&> // false
*/
#define FOLLY_CREATE_MEMBER_INVOKE_TRAITS(classname, membername) \
struct classname##__folly_detail_member_invoke { \
......
......@@ -114,27 +114,27 @@ TEST_F(InvokeTest, invoke_result) {
}
TEST_F(InvokeTest, is_invocable) {
EXPECT_TRUE((folly::is_invocable<Fn, int, char>::value));
EXPECT_TRUE((folly::is_invocable<Fn, int, char*>::value));
EXPECT_FALSE((folly::is_invocable<Fn, int>::value));
EXPECT_TRUE((folly::is_invocable_v<Fn, int, char>));
EXPECT_TRUE((folly::is_invocable_v<Fn, int, char*>));
EXPECT_FALSE((folly::is_invocable_v<Fn, int>));
}
TEST_F(InvokeTest, is_invocable_r) {
EXPECT_TRUE((folly::is_invocable_r<int, Fn, int, char>::value));
EXPECT_TRUE((folly::is_invocable_r<int, Fn, int, char*>::value));
EXPECT_FALSE((folly::is_invocable_r<int, Fn, int>::value));
EXPECT_TRUE((folly::is_invocable_r_v<int, Fn, int, char>));
EXPECT_TRUE((folly::is_invocable_r_v<int, Fn, int, char*>));
EXPECT_FALSE((folly::is_invocable_r_v<int, Fn, int>));
}
TEST_F(InvokeTest, is_nothrow_invocable) {
EXPECT_TRUE((folly::is_nothrow_invocable<Fn, int, char>::value));
EXPECT_FALSE((folly::is_nothrow_invocable<Fn, int, char*>::value));
EXPECT_FALSE((folly::is_nothrow_invocable<Fn, int>::value));
EXPECT_TRUE((folly::is_nothrow_invocable_v<Fn, int, char>));
EXPECT_FALSE((folly::is_nothrow_invocable_v<Fn, int, char*>));
EXPECT_FALSE((folly::is_nothrow_invocable_v<Fn, int>));
}
TEST_F(InvokeTest, is_nothrow_invocable_r) {
EXPECT_TRUE((folly::is_nothrow_invocable_r<int, Fn, int, char>::value));
EXPECT_FALSE((folly::is_nothrow_invocable_r<int, Fn, int, char*>::value));
EXPECT_FALSE((folly::is_nothrow_invocable_r<int, Fn, int>::value));
EXPECT_TRUE((folly::is_nothrow_invocable_r_v<int, Fn, int, char>));
EXPECT_FALSE((folly::is_nothrow_invocable_r_v<int, Fn, int, char*>));
EXPECT_FALSE((folly::is_nothrow_invocable_r_v<int, Fn, int>));
}
TEST_F(InvokeTest, free_invoke) {
......@@ -161,38 +161,37 @@ TEST_F(InvokeTest, free_invoke_result) {
TEST_F(InvokeTest, free_is_invocable) {
using traits = go_invoke_traits;
EXPECT_TRUE((traits::is_invocable<x::Obj, int>::value));
EXPECT_TRUE((traits::is_invocable<y::Obj, char const*>::value));
EXPECT_FALSE((traits::is_invocable<z::Obj, int>::value));
EXPECT_FALSE((traits::is_invocable<float>::value));
EXPECT_TRUE((traits::is_invocable_v<x::Obj, int>));
EXPECT_TRUE((traits::is_invocable_v<y::Obj, char const*>));
EXPECT_FALSE((traits::is_invocable_v<z::Obj, int>));
EXPECT_FALSE((traits::is_invocable_v<float>));
}
TEST_F(InvokeTest, free_is_invocable_r) {
using traits = go_invoke_traits;
EXPECT_TRUE((traits::is_invocable_r<int, x::Obj, int>::value));
EXPECT_TRUE((traits::is_invocable_r<char, y::Obj, char const*>::value));
EXPECT_FALSE((traits::is_invocable_r<float, z::Obj, int>::value));
EXPECT_FALSE((traits::is_invocable_r<from_any, float>::value));
EXPECT_TRUE((traits::is_invocable_r_v<int, x::Obj, int>));
EXPECT_TRUE((traits::is_invocable_r_v<char, y::Obj, char const*>));
EXPECT_FALSE((traits::is_invocable_r_v<float, z::Obj, int>));
EXPECT_FALSE((traits::is_invocable_r_v<from_any, float>));
}
TEST_F(InvokeTest, free_is_nothrow_invocable) {
using traits = go_invoke_traits;
EXPECT_TRUE((traits::is_nothrow_invocable<x::Obj, int>::value));
EXPECT_FALSE((traits::is_nothrow_invocable<y::Obj, char const*>::value));
EXPECT_FALSE((traits::is_nothrow_invocable<z::Obj, int>::value));
EXPECT_FALSE((traits::is_nothrow_invocable<float>::value));
EXPECT_TRUE((traits::is_nothrow_invocable_v<x::Obj, int>));
EXPECT_FALSE((traits::is_nothrow_invocable_v<y::Obj, char const*>));
EXPECT_FALSE((traits::is_nothrow_invocable_v<z::Obj, int>));
EXPECT_FALSE((traits::is_nothrow_invocable_v<float>));
}
TEST_F(InvokeTest, free_is_nothrow_invocable_r) {
using traits = go_invoke_traits;
EXPECT_TRUE((traits::is_nothrow_invocable_r<int, x::Obj, int>::value));
EXPECT_FALSE(
(traits::is_nothrow_invocable_r<char, y::Obj, char const*>::value));
EXPECT_FALSE((traits::is_nothrow_invocable_r<float, z::Obj, int>::value));
EXPECT_FALSE((traits::is_nothrow_invocable_r<from_any, float>::value));
EXPECT_TRUE((traits::is_nothrow_invocable_r_v<int, x::Obj, int>));
EXPECT_FALSE((traits::is_nothrow_invocable_r_v<char, y::Obj, char const*>));
EXPECT_FALSE((traits::is_nothrow_invocable_r_v<float, z::Obj, int>));
EXPECT_FALSE((traits::is_nothrow_invocable_r_v<from_any, float>));
}
TEST_F(InvokeTest, free_invoke_swap) {
......@@ -242,31 +241,31 @@ TEST_F(InvokeTest, member_invoke_result) {
TEST_F(InvokeTest, member_is_invocable) {
using traits = test_invoke_traits;
EXPECT_TRUE((traits::is_invocable<Obj, int, char>::value));
EXPECT_TRUE((traits::is_invocable<Obj, int, char*>::value));
EXPECT_FALSE((traits::is_invocable<Obj, int>::value));
EXPECT_TRUE((traits::is_invocable_v<Obj, int, char>));
EXPECT_TRUE((traits::is_invocable_v<Obj, int, char*>));
EXPECT_FALSE((traits::is_invocable_v<Obj, int>));
}
TEST_F(InvokeTest, member_is_invocable_r) {
using traits = test_invoke_traits;
EXPECT_TRUE((traits::is_invocable_r<int, Obj, int, char>::value));
EXPECT_TRUE((traits::is_invocable_r<int, Obj, int, char*>::value));
EXPECT_FALSE((traits::is_invocable_r<int, Obj, int>::value));
EXPECT_TRUE((traits::is_invocable_r_v<int, Obj, int, char>));
EXPECT_TRUE((traits::is_invocable_r_v<int, Obj, int, char*>));
EXPECT_FALSE((traits::is_invocable_r_v<int, Obj, int>));
}
TEST_F(InvokeTest, member_is_nothrow_invocable) {
using traits = test_invoke_traits;
EXPECT_TRUE((traits::is_nothrow_invocable<Obj, int, char>::value));
EXPECT_FALSE((traits::is_nothrow_invocable<Obj, int, char*>::value));
EXPECT_FALSE((traits::is_nothrow_invocable<Obj, int>::value));
EXPECT_TRUE((traits::is_nothrow_invocable_v<Obj, int, char>));
EXPECT_FALSE((traits::is_nothrow_invocable_v<Obj, int, char*>));
EXPECT_FALSE((traits::is_nothrow_invocable_v<Obj, int>));
}
TEST_F(InvokeTest, member_is_nothrow_invocable_r) {
using traits = test_invoke_traits;
EXPECT_TRUE((traits::is_nothrow_invocable_r<int, Obj, int, char>::value));
EXPECT_FALSE((traits::is_nothrow_invocable_r<int, Obj, int, char*>::value));
EXPECT_FALSE((traits::is_nothrow_invocable_r<int, Obj, int>::value));
EXPECT_TRUE((traits::is_nothrow_invocable_r_v<int, Obj, int, char>));
EXPECT_FALSE((traits::is_nothrow_invocable_r_v<int, Obj, int, char*>));
EXPECT_FALSE((traits::is_nothrow_invocable_r_v<int, Obj, int>));
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment