Skip to content

Instantly share code, notes, and snippets.

@b1ackviking
Created September 10, 2022 14:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save b1ackviking/6a73add2565b1af227aa5c4dc8daa988 to your computer and use it in GitHub Desktop.
Save b1ackviking/6a73add2565b1af227aa5c4dc8daa988 to your computer and use it in GitHub Desktop.
#include <cstddef>
#include <tuple>
template<class F>
struct function_traits;
// function pointer
template<class R, class... Args>
struct function_traits<R(*)(Args...)> : public function_traits<R(Args...)>
{};
template<class R, class... Args>
struct function_traits<R(Args...)>
{
using return_type = R;
static constexpr std::size_t arity = sizeof...(Args);
template <std::size_t N>
struct argument
{
static_assert(N < arity, "error: invalid parameter index.");
using type = typename std::tuple_element<N,std::tuple<Args...>>::type;
};
};
// member function pointer
template<class C, class R, class... Args>
struct function_traits<R(C::*)(Args...)> : public function_traits<R(C&,Args...)>
{};
// const member function pointer
template<class C, class R, class... Args>
struct function_traits<R(C::*)(Args...) const> : public function_traits<R(C&,Args...)>
{};
// member object pointer
template<class C, class R>
struct function_traits<R(C::*)> : public function_traits<R(C&)>
{};
// functor
template<class F>
struct function_traits
{
private:
using call_type = function_traits<decltype(&F::operator())>;
public:
using return_type = typename call_type::return_type;
static constexpr std::size_t arity = call_type::arity - 1;
template <std::size_t N>
struct argument
{
static_assert(N < arity, "error: invalid parameter index.");
using type = typename call_type::template argument<N+1>::type;
};
};
template<class F>
struct function_traits<F&> : public function_traits<F>
{};
template<class F>
struct function_traits<F&&> : public function_traits<F>
{};
#include <type_traits>
static_assert(std::is_same_v<function_traits<int(*)(float, double)>::return_type, int>);
static_assert(std::is_same_v<function_traits<int(*)(float, double)>::argument<0>::type, float>);
static_assert(std::is_same_v<function_traits<int(*)(float, double)>::argument<1>::type, double>);
static_assert(function_traits<int(*)(float, double)>::arity == 2);
using lambda = decltype([](float, double) {return 0;});
static_assert(std::is_same_v<function_traits<lambda>::return_type, int>);
static_assert(std::is_same_v<function_traits<lambda>::return_type, int>);
static_assert(std::is_same_v<function_traits<lambda>::argument<0>::type, float>);
static_assert(std::is_same_v<function_traits<lambda>::argument<1>::type, double>);
static_assert(function_traits<lambda>::arity == 2);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment