Получить тип возвращаемого значения в C++
Предположим, у нас есть функция f
который возвращает значение некоторого неизвестного типа (давайте назовем его T
) и принимает значение типа T
в качестве аргумента (и, возможно, имеет некоторые другие аргументы). Как я могу получить тип возврата f
в C++14?
Есть способ сделать это, если мы знаем известные типы аргументов (через std::result_of
). Возможно ли, если мы знаем все типы аргументов, кроме T
?
Пример:
template <class F> // F is functor with T operator()(T a, T b)
class A {
// Here I want to do
// T some_function(T some_arg) { ... }
}
2 ответа
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;
Тестовое задание:
#include <type_traits>
struct Functor
{
int operator()(int i, int j) { return i + j; }
};
template <class F>
struct A
{
using T = return_type_t<decltype(&F::operator())>;
T some_function(T some_arg) { return some_arg; }
};
int main()
{
A<Functor> a;
static_assert(std::is_same<decltype(a.some_function(1)), int>::value, "!");
}
Опираясь на отличный ответ @Piotr S., для произвольных типов функторов, если вы знаете, что есть только один operator()
перегрузите с правильным "шаблоном", так сказать, тогда вы можете сделать что-то вроде этого:
// leave undefined
template<class C, class T>
T return_type_helper(T (C::*)(T));
template<class C, class T>
T return_type_helper(T (C::*)(T) const);
// 10 additional combinations of ref- and cv- qualifiers omitted, because I'm lazy
template<typename T>
using functor_return_type = decltype(return_type_helper(&T::operator()));
Это активирует разрешение перегрузки и вывод аргумента шаблона для определения правильного operator()
,
И тогда вы можете объединить эти два:
template <typename... T>
struct voider { using type = void; };
template <typename... T>
using void_t = typename voider<T...>::type;
template<typename T, typename = void>
struct combined_return_type;
template<typename T>
struct combined_return_type<T, void_t<typename return_type<T>::type>> {
using type = typename return_type<T>::type;
};
template<typename T>
struct combined_return_type<T, void_t<functor_return_type<T>>> {
using type = functor_return_type<T>;
};
template <typename T>
using return_type_t = typename combined_return_type<T>::type;