204 lines
6.7 KiB
C++
204 lines
6.7 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));
|
|
}
|
|
|
|
/*!
|
|
* \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
|