Last active
March 30, 2020 18:09
-
-
Save LesleyLai/9acfb6a3a1c22cb4fbd20eaf9345a9b1 to your computer and use it in GitHub Desktop.
Given an invocable object, discover its return type and the function type
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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>); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This implementation is copied from my little library beyond::functions.