1 // Copyright 2018 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef LIB_FIT_TRAITS_H_ 6 #define LIB_FIT_TRAITS_H_ 7 8 #include <tuple> 9 #include <type_traits> 10 11 namespace fit { 12 13 // C++ 14 compatible implementation of std::void_t. 14 #if defined(__cplusplus) && __cplusplus >= 201703L 15 template <typename... T> 16 using void_t = std::void_t<T...>; 17 #else 18 template <typename... T> 19 struct make_void { typedef void type; }; 20 template <typename... T> 21 using void_t = typename make_void<T...>::type; 22 #endif 23 24 // Encapsulates capture of a parameter pack. Typical use is to use instances of this empty struct 25 // for type dispatch in function template deduction/overload resolution. 26 // 27 // Example: 28 // template <typename Callable, typename... Args> 29 // auto inspect_args(Callable c, parameter_pack<Args...>) { 30 // // do something with Args... 31 // } 32 // 33 // template <typename Callable> 34 // auto inspect_args(Callable c) { 35 // return inspect_args(std::move(c), typename callable_traits<Callable>::args{}); 36 // } 37 template <typename... T> 38 struct parameter_pack { 39 static constexpr size_t size = sizeof...(T); 40 41 template <size_t i> 42 using at = typename std::tuple_element_t<i, std::tuple<T...>>; 43 }; 44 45 // |callable_traits| captures elements of interest from function-like types (functions, function 46 // pointers, and functors, including lambdas). Due to common usage patterns, const and non-const 47 // functors are treated identically. 48 // 49 // Member types: 50 // |args| - a |parameter_pack| that captures the parameter types of the function. See 51 // |parameter_pack| for usage and details. 52 // |return_type| - the return type of the function. 53 // |type| - the underlying functor or function pointer type. This member is absent if 54 // |callable_traits| are requested for a raw function signature (as opposed to a 55 // function pointer or functor; e.g. |callable_traits<void()>|). 56 // |signature| - the type of the equivalent function. 57 58 template <typename T> 59 struct callable_traits : public callable_traits<decltype(&T::operator())> {}; 60 61 // Treat mutable call operators the same as const call operators. 62 // 63 // It would be equivalent to erase the const instead, but the common case is lambdas, which are 64 // const, so prefer to nest less deeply for the common const case. 65 template <typename FunctorType, typename ReturnType, typename... ArgTypes> 66 struct callable_traits<ReturnType (FunctorType::*)(ArgTypes...)> 67 : public callable_traits<ReturnType (FunctorType::*)(ArgTypes...) const> {}; 68 69 // Common functor specialization. 70 template <typename FunctorType, typename ReturnType, typename... ArgTypes> 71 struct callable_traits<ReturnType (FunctorType::*)(ArgTypes...) const> 72 : public callable_traits<ReturnType (*)(ArgTypes...)> { 73 74 using type = FunctorType; 75 }; 76 77 // Function pointer specialization. 78 template <typename ReturnType, typename... ArgTypes> 79 struct callable_traits<ReturnType (*)(ArgTypes...)> 80 : public callable_traits<ReturnType(ArgTypes...)> { 81 82 using type = ReturnType (*)(ArgTypes...); 83 }; 84 85 // Base specialization. 86 template <typename ReturnType, typename... ArgTypes> 87 struct callable_traits<ReturnType(ArgTypes...)> { 88 using signature = ReturnType(ArgTypes...); 89 using return_type = ReturnType; 90 using args = parameter_pack<ArgTypes...>; 91 92 callable_traits() = delete; 93 }; 94 95 // Determines whether a type has an operator() that can be invoked. 96 template <typename T, typename = void_t<>> 97 struct is_callable : public std::false_type {}; 98 template <typename ReturnType, typename... ArgTypes> 99 struct is_callable<ReturnType (*)(ArgTypes...)> 100 : public std::true_type {}; 101 template <typename FunctorType, typename ReturnType, typename... ArgTypes> 102 struct is_callable<ReturnType (FunctorType::*)(ArgTypes...)> 103 : public std::true_type {}; 104 template <typename T> 105 struct is_callable<T, void_t<decltype(&T::operator())>> 106 : public std::true_type {}; 107 108 } // namespace fit 109 110 #endif // LIB_FIT_TRAITS_H_ 111