/* * Copyright 2018 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkCallableTraits_DEFINED #define SkCallableTraits_DEFINED #include <type_traits> template <typename R, typename... Args> struct sk_base_callable_traits { using return_type = R; static constexpr std::size_t arity = sizeof...(Args); template <std::size_t N> struct argument { static_assert(N < arity, ""); using type = typename std::tuple_element<N, std::tuple<Args...>>::type; }; }; #define SK_CALLABLE_TRAITS__COMMA , #define SK_CALLABLE_TRAITS__VARARGS(quals, _) \ SK_CALLABLE_TRAITS__INSTANCE(quals,) \ SK_CALLABLE_TRAITS__INSTANCE(quals, SK_CALLABLE_TRAITS__COMMA ...) #ifdef __cpp_noexcept_function_type #define SK_CALLABLE_TRAITS__NE_VARARGS(quals, _) \ SK_CALLABLE_TRAITS__VARARGS(quals,) \ SK_CALLABLE_TRAITS__VARARGS(quals noexcept,) #else #define SK_CALLABLE_TRAITS__NE_VARARGS(quals, _) \ SK_CALLABLE_TRAITS__VARARGS(quals,) #endif #define SK_CALLABLE_TRAITS__REF_NE_VARARGS(quals, _) \ SK_CALLABLE_TRAITS__NE_VARARGS(quals,) \ SK_CALLABLE_TRAITS__NE_VARARGS(quals &,) \ SK_CALLABLE_TRAITS__NE_VARARGS(quals &&,) #define SK_CALLABLE_TRAITS__CV_REF_NE_VARARGS() \ SK_CALLABLE_TRAITS__REF_NE_VARARGS(,) \ SK_CALLABLE_TRAITS__REF_NE_VARARGS(const,) \ SK_CALLABLE_TRAITS__REF_NE_VARARGS(volatile,) \ SK_CALLABLE_TRAITS__REF_NE_VARARGS(const volatile,) /** Infer the return_type and argument<N> of a callable type T. */ template <typename T> struct SkCallableTraits : SkCallableTraits<decltype(&T::operator())> {}; // function (..., (const, volatile), (&, &&), noexcept) #define SK_CALLABLE_TRAITS__INSTANCE(quals, varargs) \ template <typename R, typename... Args> \ struct SkCallableTraits<R(Args... varargs) quals> : sk_base_callable_traits<R, Args...> {}; SK_CALLABLE_TRAITS__CV_REF_NE_VARARGS() #undef SK_CALLABLE_TRAITS__INSTANCE // pointer to function (..., noexcept) #define SK_CALLABLE_TRAITS__INSTANCE(quals, varargs) \ template <typename R, typename... Args> \ struct SkCallableTraits<R(*)(Args... varargs) quals> : sk_base_callable_traits<R, Args...> {}; SK_CALLABLE_TRAITS__NE_VARARGS(,) #undef SK_CALLABLE_TRAITS__INSTANCE // pointer to method (..., (const, volatile), (&, &&), noexcept) #define SK_CALLABLE_TRAITS__INSTANCE(quals, varargs) \ template <typename T, typename R, typename... Args> \ struct SkCallableTraits<R(T::*)(Args... varargs) quals> : sk_base_callable_traits<R, Args...> {}; SK_CALLABLE_TRAITS__CV_REF_NE_VARARGS() #undef SK_CALLABLE_TRAITS__INSTANCE // pointer to field template <typename T, typename R> struct SkCallableTraits<R T::*> : sk_base_callable_traits<typename std::add_lvalue_reference<R>::type> {}; #undef SK_CALLABLE_TRAITS__CV_REF_NE_VARARGS #undef SK_CALLABLE_TRAITS__REF_NE_VARARGS #undef SK_CALLABLE_TRAITS__NE_VARARGS #undef SK_CALLABLE_TRAITS__VARARGS #undef SK_CALLABLE_TRAITS__COMMA #endif