I'm having a hard time getting this simple thing going.
One thing I found that works:
#include <type_traits>
struct A
{
int Method();
};
static_assert( std::is_same_v<
decltype(A{}.Method()), int
>
); // pass. cool.
Ok great. But no; not great. Because I now have a default constructible requirement, AND I need to write a call expression with all arguments. And who knows about them !
Consider the real situation:
struct A
{
int Method(MysteriousArgumentsIDontCareAboutAndCanChangeInTheFuture);
};
static_assert( std::is_same_v<
decltype(A{}.Method()), int
>
); // not so cool anymore (too few arguments to function call, expected 1, have 0)
How about using std::invoke_result
?
static_assert( std::is_same_v<
std::invoke_result_t< A::Method >, int
>
);
nah.
call to non-static member function without an object argument
MSVC says
non-standard syntax; use '&' to create a pointer to member
I can fiddle all I want with this expression, nothing good comes out of it.
e.g.:
using T = std::invoke_result_t< decltype(&A::Method) >;
error: no type named 'type' in 'std::invoke_result
If I remove the decltype
it's type-value mismatch (of course) etc...
cppreference.com mentions this usage for the C++14 version:
std::result_of<decltype(&C::Func)(C, char, int&)>::type
Not much better than my first attempt. All the arguments are still there.
In action in our simple case: https://godbolt.org/z/KtQbth
Help ?
You can use the trait suggested by Piotr Skotnicki:
template <typename T>
struct return_type;
template <typename R, typename... Args>
struct return_type<R(Args...)> { using type = R; };
template <typename R, typename... Args>
struct return_type<R(*)(Args...)> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...)> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) &> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) &&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const&&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) volatile> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) volatile&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) volatile&&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const volatile> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const volatile&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const volatile&&> { using type = R; };
template <typename T>
using return_type_t = typename return_type<T>::type;
Now you can do:
static_assert(std::is_same_v<return_type_t<decltype(&A::Method)>, int>);