Skip to content

Instantly share code, notes, and snippets.

@LesleyLai
Last active March 30, 2020 18:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LesleyLai/9acfb6a3a1c22cb4fbd20eaf9345a9b1 to your computer and use it in GitHub Desktop.
Save LesleyLai/9acfb6a3a1c22cb4fbd20eaf9345a9b1 to your computer and use it in GitHub Desktop.
Given an invocable object, discover its return type and the function type
#include <type_traits>
namespace detail {
template <typename Func>
struct function_trait;
#define BEYOND_NOARG
#define BEYOND_FUNCTION_TRAIT(CV_OPT, NOEXCEPT_OPT) \
template <typename R, typename... Args> \
struct function_trait<R(Args...) CV_OPT NOEXCEPT_OPT> { \
using return_type = R; \
using function_type = R(Args...) NOEXCEPT_OPT; \
};
BEYOND_FUNCTION_TRAIT(BEYOND_NOARG, BEYOND_NOARG)
BEYOND_FUNCTION_TRAIT(const, BEYOND_NOARG)
BEYOND_FUNCTION_TRAIT(const volatile, BEYOND_NOARG)
BEYOND_FUNCTION_TRAIT(volatile, BEYOND_NOARG)
BEYOND_FUNCTION_TRAIT(BEYOND_NOARG, noexcept)
BEYOND_FUNCTION_TRAIT(const, noexcept)
BEYOND_FUNCTION_TRAIT(const volatile, noexcept)
BEYOND_FUNCTION_TRAIT(volatile, noexcept)
#undef BEYOND_FUNCTION_TRAIT
template <typename T> struct member_function_pointer_trait {
};
#define BEYOND_MEMBER_FUNCTION_POINTER_TRAIT(CV_OPT, NOEXCEPT_OPT) \
template <typename R, typename U, typename... Args> \
struct member_function_pointer_trait<R (U::*)(Args...) \
CV_OPT NOEXCEPT_OPT> { \
using return_type = R; \
using function_type = R(Args...) NOEXCEPT_OPT; \
};
BEYOND_MEMBER_FUNCTION_POINTER_TRAIT(BEYOND_NOARG, BEYOND_NOARG)
BEYOND_MEMBER_FUNCTION_POINTER_TRAIT(const, BEYOND_NOARG)
BEYOND_MEMBER_FUNCTION_POINTER_TRAIT(const volatile, BEYOND_NOARG)
BEYOND_MEMBER_FUNCTION_POINTER_TRAIT(volatile, BEYOND_NOARG)
BEYOND_MEMBER_FUNCTION_POINTER_TRAIT(BEYOND_NOARG, noexcept)
BEYOND_MEMBER_FUNCTION_POINTER_TRAIT(const, noexcept)
BEYOND_MEMBER_FUNCTION_POINTER_TRAIT(const volatile, noexcept)
BEYOND_MEMBER_FUNCTION_POINTER_TRAIT(volatile, noexcept)
#undef BEYOND_NOARG
#undef BEYOND_MEMBER_FUNCTION_POINTER_TRAIT
// Main template: cannot find &Func::operator()
template <typename Func, typename = void>
struct function_deduce_signature_impl {
};
template <typename Func>
struct function_deduce_signature_impl<
Func, std::void_t<decltype(&Func::operator())>> {
using type = member_function_pointer_trait<decltype(&Func::operator())>;
};
template <typename Func>
struct function_deduce_signature_impl<Func, std::enable_if_t<std::is_function_v<Func>>> {
using type = function_trait<Func>;
};
template <typename Func>
struct function_deduce_signature_impl<Func, std::enable_if_t<std::is_pointer_v<Func>>> {
using type = function_trait<std::remove_pointer_t<Func>>;
};
} // namespace detail
template <typename Func>
struct function_deduce_signature
: detail::function_deduce_signature_impl<Func> {
};
template <typename Func>
using function_deduce_signature_t =
typename function_deduce_signature<Func>::type;
// Tests
int f() {
return 42;
}
int f2() noexcept {
return 42;
}
auto g = []{
return 42;
};
auto g2 = []() noexcept {
return 42;
};
int main() {
static_assert(std::is_same_v<int,
function_deduce_signature_t<decltype(f)>::return_type>);
static_assert(std::is_same_v<int(),
function_deduce_signature_t<decltype(f)>::function_type>);
static_assert(std::is_same_v<int,
function_deduce_signature_t<decltype(f2)>::return_type>);
static_assert(std::is_same_v<int() noexcept,
function_deduce_signature_t<decltype(f2)>::function_type>);
static_assert(std::is_same_v<int,
function_deduce_signature_t<decltype(&f)>::return_type>);
static_assert(std::is_same_v<int(),
function_deduce_signature_t<decltype(&f)>::function_type>);
static_assert(std::is_same_v<int,
function_deduce_signature_t<decltype(&f2)>::return_type>);
static_assert(std::is_same_v<int() noexcept,
function_deduce_signature_t<decltype(&f2)>::function_type>);
static_assert(std::is_same_v<int,
function_deduce_signature_t<decltype(g)>::return_type>);
static_assert(std::is_same_v<int(),
function_deduce_signature_t<decltype(g)>::function_type>);
static_assert(std::is_same_v<int,
function_deduce_signature_t<decltype(g2)>::return_type>);
static_assert(std::is_same_v<int() noexcept,
function_deduce_signature_t<decltype(g2)>::function_type>);
}
@LesleyLai
Copy link
Author

This implementation is copied from my little library beyond::functions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment