Самый простой способ определения возвращаемого типа функции

Учитывая очень простую, но длительную функцию, такую как:

int foo(int a, int b, int c, int d) {
    return 1;
}

// using ReturnTypeOfFoo = ???

Каков самый простой и сжатый способ определения возвращаемого типа функции (ReturnTypeOfFoo, в этом примере: int) во время компиляции без повторения типов параметров функции (только по имени, поскольку известно, что функция не имеет никаких дополнительных перегрузок )?

Ответ 1

Здесь вы можете использовать std::function, который даст вам псевдоним для типа возвращаемого значения функции. Для этого требуется поддержка С++ 17, поскольку он опирается на вычет аргументов шаблона класса, но он будет работать с любым вызываемым типом:

using ReturnTypeOfFoo = decltype(std::function{foo})::result_type;

Мы можем сделать это немного более общим, как

template<typename Callable>
using return_type_of_t = 
    typename decltype(std::function{std::declval<Callable>()})::result_type;

который затем позволяет использовать его как

int foo(int a, int b, int c, int d) {
    return 1;
}

auto bar = [](){ return 1; };

struct baz_ 
{ 
    double operator()(){ return 0; } 
} baz;

using ReturnTypeOfFoo = return_type_of_t<decltype(foo)>;
using ReturnTypeOfBar = return_type_of_t<decltype(bar)>;
using ReturnTypeOfBaz = return_type_of_t<decltype(baz)>;

Ответ 2

Наиболее простым и лаконичным является, вероятно, следующее:

template <typename R, typename... Args>
R return_type_of(R(*)(Args...));

using ReturnTypeOfFoo = decltype(return_type_of(foo));

Обратите внимание, что это не будет работать для объектов функций или указателей на функции-члены. Просто функции, которые не перегружены или шаблоны, или noexcept.

Но это может быть расширено для поддержки всех этих случаев, если это необходимо, путем добавления дополнительных перегрузок return_type_of.

Ответ 3

Я не знаю, является ли самый простой способ (если вы можете использовать С++ 17, это, безусловно, не так: см. Ответ NathanOliver), но... как насчет объявления функции следующим образом:

template <typename R, typename ... Args>
R getRetType (R(*)(Args...));

и с помощью decltype()?

using ReturnTypeOfFoo = decltype( getRetType(&foo) );

Обратите внимание, что getRetType() объявлен и не определен, потому что вызывается только decltype(), поэтому релевант только возвращаемый тип.