Kylin/Universal/FunctionTraits.h
2024-09-15 16:15:26 +08:00

207 lines
6.8 KiB
C++

#ifndef FUNCTIONTRAITS_H
#define FUNCTIONTRAITS_H
#include <functional>
#include <tuple>
#include <type_traits>
template <typename T>
class FunctionTraits;
template <typename>
struct IsTuple : std::false_type {
enum {
num = 1,
};
};
template <typename... T>
struct IsTuple<std::tuple<T...>> : std::true_type {
enum {
num = std::tuple_size<std::tuple<T...>>::value,
};
};
template <typename... T>
struct IsTuple<std::pair<T...>> : std::true_type {
enum {
num = std::tuple_size<std::pair<T...>>::value,
};
};
template <typename Ret, typename... Args>
class FunctionTraits<Ret(Args...)> {
public:
enum { arity = sizeof...(Args), Results = IsTuple<Ret>::num };
using FunctionType = Ret(Args...);
using FunctionPointerType = FunctionType *;
using ReturnType = Ret;
using StlFunctionType = std::function<FunctionType>;
using Arguments = std::tuple<Args...>;
template <size_t I>
class Argument {
public:
static_assert(I < arity, "index is out of range, index must less than sizeof Args...");
using Type = std::tuple_element_t<I, Arguments>;
};
using FirstArgumentType = typename Argument<0>::Type;
};
template <typename Ret>
class FunctionTraits<Ret()> {
public:
enum { arity = 0, Results = IsTuple<Ret>::num };
using FunctionType = Ret();
using FunctionPointerType = FunctionType *;
using ReturnType = Ret;
using StlFunctionType = std::function<FunctionType>;
using Arguments = std::tuple<>;
using FirstArgumentType = void;
template <size_t I>
class Argument {
public:
using Type = void;
};
};
template <>
class FunctionTraits<std::nullptr_t> {
public:
using Arguments = std::tuple<>;
using FirstArgumentType = void;
template <size_t I>
class Argument {
public:
using Type = void;
};
};
template <typename Ret, typename... Args>
class FunctionTraits<Ret (*)(Args...)> : public FunctionTraits<Ret(Args...)> {};
template <typename Ret, typename... Args>
class FunctionTraits<std::function<Ret(Args...)>> : public FunctionTraits<Ret(Args...)> {};
template <typename Ret, typename ClassType, typename... Args>
class FunctionTraits<Ret (ClassType::*)(Args...)> : public FunctionTraits<Ret(Args...)> {};
template <typename Ret, typename ClassType, typename... Args>
class FunctionTraits<Ret (ClassType::*)(Args...) volatile> : public FunctionTraits<Ret(Args...)> {};
template <typename Ret, typename ClassType, typename... Args>
class FunctionTraits<Ret (ClassType::*)(Args...) const> : public FunctionTraits<Ret(Args...)> {};
template <typename Ret, typename ClassType, typename... Args>
class FunctionTraits<Ret (ClassType::*)(Args...) const volatile> : public FunctionTraits<Ret(Args...)> {};
// std::bind for object methods rclcpp/rclcpp/include/rclcpp/function_traits.hpp
template <typename ClassT, typename ReturnTypeT, typename... Args, typename... FArgs>
#if defined _GLIBCXX_RELEASE // glibc++ (GNU C++ >= 7.1)
struct FunctionTraits<std::_Bind<ReturnTypeT (ClassT::*(FArgs...))(Args...)>>
#elif defined __GLIBCXX__ // glibc++ (GNU C++)
struct FunctionTraits<std::_Bind<std::_Mem_fn<ReturnTypeT (ClassT::*)(Args...)>(FArgs...)>>
#elif defined _MSC_VER // MS Visual Studio
struct FunctionTraits<std::_Binder<std::_Unforced, ReturnTypeT (ClassT::*)(Args...), FArgs...>>
#elif defined __clang__
struct FunctionTraits<std::__bind<ReturnTypeT (ClassT::*(FArgs...))(Args...)>>
#else
#error "Unsupported C++ compiler / standard library"
#endif
: FunctionTraits<ReturnTypeT(Args...)> {
};
// template <typename ClassT, typename ReturnTypeT, typename... Args, typename... FArgs>
// class FunctionTraits<std::_Bind<ReturnTypeT (ClassT::*(FArgs...))(Args...)>>
// : public FunctionTraits<decltype(std::_Bind<ReturnTypeT (ClassT::*(FArgs...))(Args...)>::operator())> {};
template <typename Callable>
class FunctionTraits : public FunctionTraits<decltype(&Callable::operator())> {};
template <typename Function>
typename FunctionTraits<std::decay_t<Function>>::StlFunctionType makeStlFunction(Function &&lambda) {
return static_cast<typename FunctionTraits<std::decay_t<Function>>::StlFunctionType>(std::forward<Function>(lambda));
}
template <typename T>
using Unqualified = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
/*!
* \struct HasCallOperator
* http://stackoverflow.com/a/5117641
*/
template <typename T>
struct HasCallOperator {
template <typename U>
static char check(decltype(&U::operator(), char(0)));
template <typename U>
static char (&check(...))[2];
static const bool value = (sizeof(check<T>(0)) == 1);
};
/*!
* \struct ArgsOf
* http://stackoverflow.com/a/7943765
* http://stackoverflow.com/a/27885283
*/
template <typename... Args>
struct ArgsTraits {
using types = std::tuple<Args...>;
using first = typename std::tuple_element<0, types>::type;
static const size_t count = std::tuple_size<types>::value;
};
template <>
struct ArgsTraits<> {
using types = std::tuple<>;
using first = void;
static const size_t count = 0;
};
// Fallback implementation, including types (T) which are not functions but
// also lambda with `auto` arguments, which are not covered but still valid
// callbacks (see the QPromiseBase<T> template constructor).
template <typename T, typename Enabled = void>
struct ArgsOf : public ArgsTraits<> {};
// Partial specialization for null function.
template <>
struct ArgsOf<std::nullptr_t> : public ArgsTraits<> {};
// Partial specialization for type with a non-overloaded operator().
// This applies to lambda, std::function but not to std::bind result.
template <typename T>
struct ArgsOf<T, typename std::enable_if<HasCallOperator<T>::value>::type> : public ArgsOf<decltype(&T::operator())> {};
// Partial specialization to remove reference and rvalue (e.g. lambda, std::function, etc.).
template <typename T>
struct ArgsOf<T &> : public ArgsOf<T> {};
template <typename T>
struct ArgsOf<T &&> : public ArgsOf<T> {};
// Partial specialization for function type.
template <typename R, typename... Args>
struct ArgsOf<R(Args...)> : public ArgsTraits<Args...> {};
// Partial specialization for function pointer.
template <typename R, typename... Args>
struct ArgsOf<R (*)(Args...)> : public ArgsTraits<Args...> {};
// Partial specialization for pointer-to-member-function (i.e. operator()'s).
template <typename R, typename T, typename... Args>
struct ArgsOf<R (T::*)(Args...)> : public ArgsTraits<Args...> {};
template <typename R, typename T, typename... Args>
struct ArgsOf<R (T::*)(Args...) const> : public ArgsTraits<Args...> {};
template <typename R, typename T, typename... Args>
struct ArgsOf<R (T::*)(Args...) volatile> : public ArgsTraits<Args...> {};
template <typename R, typename T, typename... Args>
struct ArgsOf<R (T::*)(Args...) const volatile> : public ArgsTraits<Args...> {};
#endif // FUNCTIONTRAITS_H