Как вывести тип возвращаемого значения функтора?

Я хотел бы написать функцию шаблона, которая принимает 2 значения и функтор или лямбда. Функция вызывает функтор с этими значениями и возвращает результат.

template <typename T, typename Fn> 
_ReturnTypeOfPred_ Apply(T x, T y, Fn fn)
  {
  return fn(x, y);
  }

Вопрос. Как определить возвращаемый тип Apply, чтобы он стал равным типу возврата Fn? Это не обязательно равно T, как в этом примере функтора

template <typename T> 
auto Sum(T x, T y) -> decltype(x+y)
  {
  return x+y;
  }

Обновление

Первый пример был упрощен. Должен ли он работать?

template <typename TContainer, typename Fn> 
auto Apply(const TContainer& x, const TContainer& y, Fn fn) -> decltype(fn(x.front(), y.front()))
  {
  return fn(x.front(), y.front());
  }

Будет ли он работать, если я повторяю выражение return в decltype возвращаемого типа? Есть ли более элегантный способ?

Ответ 1

Ты почти там; просто используйте decltype:

template <typename T, typename Fn> 
auto Apply(T x, T y, Fn fn) -> decltype(fn(x, y))
{
  return fn(x, y);
}

Вы можете использовать std::result_of (Разницу между std:: result_of и decltype), но зачем беспокоиться?

template <typename T, typename Fn> 
typename std::result_of<Fn, T, T>::type Apply(T x, T y, Fn fn)
{
  return fn(x, y);
}

Относительно следующего вопроса: для функции

auto fn(<args>) -> <return-type> { return <expression>; }

замена return-type на decltype(<expression>) обычно будет работать, но может быть подвержена ошибкам. Например, рассмотрим:

auto f(char c) -> decltype(std::string() += c) { return std::string() += c; }

Здесь decltype даст std::string &, и ваша функция вернет ссылку lvalue на локальный! Это должно быть изменено на:

auto f(char c) -> std::remove_reference<decltype(std::string() += c)>::type {
    return std::string() += c;
}

В других случаях <expression> может давать значение, которое не может быть возвращено из-за того, что оно является, например, noncopyable, содержащий лямбда и т.д.