С++-шаблон функции: Производный и явный тип возвращаемого значения

У меня есть следующая проблема: я просто не вижу правильного решения (и, возможно, ее нет): у меня есть шаблонный метод, в котором тип возврата зависит от типа ввода и благодаря С++ 11 decltype тип возврата может быть легко получен, но я также хотел бы позволить пользователю явно определять тип возвращаемого значения, если это необходимо.

Более формально у меня есть шаблонная функция f, которую я хотел бы назвать вызываемым как f(x), при этом ни тип ввода, ни возвращаемый тип явно не определены. И я также хотел бы иметь возможность называть его как f<ret_t>x() с явно выраженным типом возвращаемого значения, но тип ввода все равно получается автоматически.

Теперь, удовлетворяя первому ограничению с С++ 11, легко (предположим, что есть еще один шаблонный метод:

template<typename InT>
auto f(const InT& in) -> decltype(/* code deriving the return type using in */);

Но это не позволит переопределить возвращаемый тип, для этого мне пришлось бы добавить его в качестве второго параметра шаблона и переместить вывод decltype в определение шаблона и, вероятно, нужно будет использовать std::declval<InT> или std::result_of

template<
    typename InT,
    typename RetT = /* code deriving return type using InT and declval/result_of */>
RetT f(const InT& in);

Тем не менее, при вызове f мне всегда нужно также явно определять InT. Таким образом, объявление f для того, чтобы оставить InT открытым, но указать RetT должно быть:

template<
    typename RetT = /* code deriving return type using InT and declval/result_of */,
    typename InT>
RetT f(const InT& in);

Но так как в точке, где мне нужно указать значение по умолчанию для RetT, InT пока недоступно и, следовательно, не может быть использовано.

Лучшее обходное решение, которое я мог бы придумать до сих пор, которое не очень удовлетворительно и, похоже, не работает, поскольку вычет RetT не выполняется (видимо, из-за того, что вы не можете выводить типы из аргументов по умолчанию), есть:

template<typename RetT, typename InT>
RetT f(
    const InT& in,
    const RetT& = std::declval</* code deriving return type using InT or in and declval/result_of */>());

Есть ли лучшие способы иметь значение по умолчанию для RetT, которое зависит от InT, но при этом может явно указывать RetT, если это необходимо? Важно отметить, что тип возвращаемого значения должен быть доступен в реализации функции для того, чтобы объект RetT был назначен напрямую и только один раз внутри тела метода.

Ответ 1

Вы можете использовать типы std::conditional и dummy, чтобы проверить, имеет ли функция автоматический выведенный тип или выбранный пользователем тип.

Если пользователь явно выбирает тип возврата, тип возвращаемого значения будет чем-то иным, чем тип dummy, и это будет тип возвращаемого значения функции. В противном случае просто используйте выведенный тип, как и раньше.

Следуя примеру использования:

#include <typeindex>
#include <type_traits>
#include <iostream>

struct dummy
{
};

template<typename RetType = dummy, typename T>
auto f(const T& in)
-> typename std::conditional<std::is_same<RetType, dummy>::value, T, RetType>::type
{
    std::cout<<typeid(RetType).name()<<" "<<typeid(T).name()<<std::endl;
    return in;
}

int main()
{
    f(1);
    f<float>(1);
}