Могу ли я получить тип возврата функции из подписи?

Итак, у меня есть масса функций, похожих на эти:

template <typename T>
bool Zero(const T, const T, const T);
template <typename T>
T One(const T, const T, const T, bool);
template <typename T>
T Three(const T, const T, const T, const T, const T, const T);

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

template <typename T>
decltype(Zero<decltype(declval<T>().x)>(decltype(declval<decltype(declval<T>().x)>()), decltype(declval<decltype(declval<T>().x)>()), decltype(declval<decltype(declval<T>().x)>()))) ZeroWrapper(const T);
template <typename T>
decltype(One<decltype(declval<T>().x)>(decltype(declval<decltype(declval<T>().x)>()), decltype(declval<decltype(declval<T>().x)>()), decltype(declval<decltype(declval<T>().x)>()), bool())) OneWrapper(const T);
template <typename T>
decltype(Three<decltype(declval<T>().x)>(decltype(declval<decltype(declval<T>().x)>()), decltype(declval<decltype(declval<T>().x)>()), decltype(declval<decltype(declval<T>().x)>()), decltype(declval<decltype(declval<T>().x)>()), decltype(declval<decltype(declval<T>().x)>()), decltype(declval<decltype(declval<T>().x)>()))) ThreeWrapper(const T);

Как видите, читать все эти decltype(declval<T>().x) ужасно трудно. Могу ли я создать шаблон using или есть какая-то стандартная функция, которая позволит мне извлечь тип возвращаемого значения из указателя функции без передачи типов аргументов в decltype или result_of? Так что-то вроде этого:

template <typename T>
foo_t<Zero<decltype(declval<T>().x)>> ZeroWrapper(const T);
template <typename T>
foo_t<One<decltype(declval<T>().x)>> OneWrapper(const T);
template <typename T>
foo_t<Three<decltype(declval<T>().x)>> ThreeWrapper(const T);

person Jonathan Mee    schedule 04.03.2019    source источник
comment
Помогает ли это: stackoverflow.com/q/54827950/5470596?   -  person YSC    schedule 04.03.2019
comment
decltype(declval<decltype(declval<T>().x)>()) похоже на тупик. Почему бы просто не ввести псевдоним it для чего-нибудь и уменьшить шаблон?   -  person Dan M.    schedule 04.03.2019
comment
Живая демонстрация: coliru.stacked-crooked.com/a/ecdbe6b6260cb7c0;)   -  person YSC    schedule 04.03.2019
comment
@YSC похоже, что они вызывают функции с полем .x в оболочке в примере вопроса.   -  person Dan M.    schedule 04.03.2019
comment
Кроме того, пробовали ли вы просто использовать вычет типа auto? Или конечный тип возврата auto ZeroWrapper(const T arg) -> decltype(Zero(arg.x));?   -  person Dan M.    schedule 04.03.2019
comment
@DanM. Я не уверен, что это действительно имеет значение ... Могу ли я использовать шаблон using или существует ли какая-то стандартная функция, которая позволит мне извлечь тип возвращаемого значения из указателя функции без передачи типов аргументов в decltype или result_of?   -  person YSC    schedule 04.03.2019
comment
Я отвечу правильно, и пусть сама система очков решит ^^   -  person YSC    schedule 04.03.2019
comment
Zero<decltype(declval<T>().x)> - Ожидаете ли вы, что T будет ссылочным типом (возможно, только если явно указано)? И намерены поддержать дело? Если нет, то declval<T>().x здесь можно заменить на более читаемый T::x   -  person StoryTeller - Unslander Monica    schedule 04.03.2019
comment
@DanM. Я не пробовал вычитать шрифты ... Честно говоря, я знаю, что это вещь ... Я просто не знаком с тем, как это использовать.   -  person Jonathan Mee    schedule 04.03.2019
comment
@JonathanMee во многих случаях вы можете просто использовать auto в качестве возвращаемого типа, и если ваша функция достаточно проста, она будет работать.   -  person Dan M.    schedule 04.03.2019
comment
@DanM. К сожалению, это функции-обертки для игрушек. Мои настоящие функции-оболочки нуждаются в возвращаемом типе для большего количества метапрограммирования как части вызова enable_if.   -  person Jonathan Mee    schedule 04.03.2019


Ответы (2)


Могу ли я использовать шаблон использования или существует ли какая-то стандартная функция, которая позволит мне извлечь тип возвращаемого значения из указателя функции без передачи типов аргументов в decltype или result_of?

Да!

#include <tuple>
#include <functional>

template<class T>
struct callable_trait
{};

template<class R, class... Args>
struct callable_trait<std::function<R(Args...)>>
{
    using return_type    = R;
    using argument_types = std::tuple<Args...>;
};

template<auto callable>
using return_type = typename callable_trait<decltype(std::function{callable})>::return_type;

return_type<some_callable> - это тип, возвращаемый some_callable при вызове с соответствующими аргументами. Здесь используется std::function, чтобы обеспечить специализацию для каждого возможного вида вызываемого (бесплатная функция, указатель на функцию, функция-член, объект-функтор). Это объясняется в этом ответе StackOverflow.


В вашем случае вы можете использовать это так:

template <typename T>
bool Zero(const T, const T, const T);
template <typename T>
T One(const T, const T, const T, bool);
template <typename T>
T Three(const T, const T, const T, const T, const T, const T);

template <typename T>
return_type<Zero<T>>  ZeroWrapper(const T);
template <typename T>
return_type<One<T>>   OneWrapper(const T);
template <typename T>
return_type<Three<T>> ThreeWrapper(const T);

Полная демонстрация

person YSC    schedule 04.03.2019
comment
Это работает как шарм ... в основном ... Я застрял на более старой версии Visual Studio 2017, которая не поддерживает параметры шаблона auto. Я пытаюсь обойти это без необходимости передавать два параметра шаблона в _2 _... Если у вас есть какие-либо предложения ... - person Jonathan Mee; 04.03.2019
comment
Да, похоже, это должно было сработать, но я получаю сообщение об ошибке: ошибка C2955: std::function: для использования шаблона класса требуется список аргументов шаблона - person Jonathan Mee; 04.03.2019

В c ++ 17 объект function снабжен элементом Руководство по дедукции, которое позволяет определить его тип по аргументу, переданному конструктору. Так, например, с учетом функции int foo() в c ++ 11 нам нужно было сделать:

function<int()> bar(foo);

В c ++ 17 Тип function<int()> bar будет производным, если мы просто:

function bar(foo);

Таким образом, мы можем использовать Руководство по дедукции для заполнения временного function только подписью; таким образом используя result_type function, чтобы найти результат ваших вспомогательных функций:

template <typename T>
typename decltype(function(Zero<decltype(declval<T>().x)>))::return_type ZeroWrapper(const T);
template <typename T>
typename decltype(function(One<decltype(declval<T>().x)>))::return_type OneWrapper(const T);
template <typename T>
typename decltype(function(Three<decltype(declval<T>().x)>))::return_type ThreeWrapper(const T);

Живой пример

person Jonathan Mee    schedule 04.03.2019
comment
Стоит отметить, что, хотя это действительно решает проблему для компиляторов C ++ 17, это не решает ее для Visual Studio 15.6.7, которую я застрял в использовании, поскольку он не соответствует C ++ 17, что может быть очевидным, поскольку Я спрашиваю о result_of, а не о invoke_result. - person Jonathan Mee; 04.03.2019
comment
Я нашел здесь потенциальный обходной путь: stackoverflow.com/q/54990207/2642059, который работает на C ++ 14. .. но, к сожалению, все еще не работает в Visual Studio 15.6.7: stackoverflow.com/q/55047417 / 2642059 - person Jonathan Mee; 07.03.2019
comment
Последнее обновление, здесь я определил решение C ++ 14 / Visual Studio 15.6.7: stackoverflow.com/a/55050902/2642059 < / а> - person Jonathan Mee; 11.03.2019