Kylin/Universal/FunctionTraits.h

128 lines
4.2 KiB
C
Raw Normal View History

2023-07-21 11:21:16 +08:00
#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));
}
#endif // FUNCTIONTRAITS_H