1 | /* |
2 | * Copyright 2018 Google Inc. |
3 | * |
4 | * Use of this source code is governed by a BSD-style license that can be |
5 | * found in the LICENSE file. |
6 | */ |
7 | |
8 | #ifndef SkCallableTraits_DEFINED |
9 | #define SkCallableTraits_DEFINED |
10 | |
11 | #include <type_traits> |
12 | #include <tuple> |
13 | |
14 | template <typename R, typename... Args> struct sk_base_callable_traits { |
15 | using return_type = R; |
16 | static constexpr std::size_t arity = sizeof...(Args); |
17 | template <std::size_t N> struct argument { |
18 | static_assert(N < arity, "" ); |
19 | using type = typename std::tuple_element<N, std::tuple<Args...>>::type; |
20 | }; |
21 | }; |
22 | |
23 | #define SK_CALLABLE_TRAITS__COMMA , |
24 | |
25 | #define SK_CALLABLE_TRAITS__VARARGS(quals, _) \ |
26 | SK_CALLABLE_TRAITS__INSTANCE(quals,) \ |
27 | SK_CALLABLE_TRAITS__INSTANCE(quals, SK_CALLABLE_TRAITS__COMMA ...) |
28 | |
29 | #ifdef __cpp_noexcept_function_type |
30 | #define SK_CALLABLE_TRAITS__NE_VARARGS(quals, _) \ |
31 | SK_CALLABLE_TRAITS__VARARGS(quals,) \ |
32 | SK_CALLABLE_TRAITS__VARARGS(quals noexcept,) |
33 | #else |
34 | #define SK_CALLABLE_TRAITS__NE_VARARGS(quals, _) \ |
35 | SK_CALLABLE_TRAITS__VARARGS(quals,) |
36 | #endif |
37 | |
38 | #define SK_CALLABLE_TRAITS__REF_NE_VARARGS(quals, _) \ |
39 | SK_CALLABLE_TRAITS__NE_VARARGS(quals,) \ |
40 | SK_CALLABLE_TRAITS__NE_VARARGS(quals &,) \ |
41 | SK_CALLABLE_TRAITS__NE_VARARGS(quals &&,) |
42 | |
43 | #define SK_CALLABLE_TRAITS__CV_REF_NE_VARARGS() \ |
44 | SK_CALLABLE_TRAITS__REF_NE_VARARGS(,) \ |
45 | SK_CALLABLE_TRAITS__REF_NE_VARARGS(const,) \ |
46 | SK_CALLABLE_TRAITS__REF_NE_VARARGS(volatile,) \ |
47 | SK_CALLABLE_TRAITS__REF_NE_VARARGS(const volatile,) |
48 | |
49 | /** Infer the return_type and argument<N> of a callable type T. */ |
50 | template <typename T> struct SkCallableTraits : SkCallableTraits<decltype(&T::operator())> {}; |
51 | |
52 | // function (..., (const, volatile), (&, &&), noexcept) |
53 | #define SK_CALLABLE_TRAITS__INSTANCE(quals, varargs) \ |
54 | template <typename R, typename... Args> \ |
55 | struct SkCallableTraits<R(Args... varargs) quals> : sk_base_callable_traits<R, Args...> {}; |
56 | |
57 | SK_CALLABLE_TRAITS__CV_REF_NE_VARARGS() |
58 | #undef SK_CALLABLE_TRAITS__INSTANCE |
59 | |
60 | // pointer to function (..., noexcept) |
61 | #define SK_CALLABLE_TRAITS__INSTANCE(quals, varargs) \ |
62 | template <typename R, typename... Args> \ |
63 | struct SkCallableTraits<R(*)(Args... varargs) quals> : sk_base_callable_traits<R, Args...> {}; |
64 | |
65 | SK_CALLABLE_TRAITS__NE_VARARGS(,) |
66 | #undef SK_CALLABLE_TRAITS__INSTANCE |
67 | |
68 | // pointer to method (..., (const, volatile), (&, &&), noexcept) |
69 | #define SK_CALLABLE_TRAITS__INSTANCE(quals, varargs) \ |
70 | template <typename T, typename R, typename... Args> \ |
71 | struct SkCallableTraits<R(T::*)(Args... varargs) quals> : sk_base_callable_traits<R, Args...> {}; |
72 | |
73 | SK_CALLABLE_TRAITS__CV_REF_NE_VARARGS() |
74 | #undef SK_CALLABLE_TRAITS__INSTANCE |
75 | |
76 | // pointer to field |
77 | template <typename T, typename R> |
78 | struct SkCallableTraits<R T::*> : sk_base_callable_traits<typename std::add_lvalue_reference<R>::type> {}; |
79 | |
80 | #undef SK_CALLABLE_TRAITS__CV_REF_NE_VARARGS |
81 | #undef SK_CALLABLE_TRAITS__REF_NE_VARARGS |
82 | #undef SK_CALLABLE_TRAITS__NE_VARARGS |
83 | #undef SK_CALLABLE_TRAITS__VARARGS |
84 | #undef SK_CALLABLE_TRAITS__COMMA |
85 | |
86 | #endif |
87 | |