Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deduce the type of the functor's return value?

I would like to write a template function which accepts 2 values and a functor or a lambda. The function calls the functor with those values and returns the result.

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

Question: How can I define the return type of Apply to become equal to the return type of Fn? It is not necessarily equal to T, as in this example of the functor

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

Update

The 1st example was oversimplified. Should this one work?

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());
  }

Would it always work if I repeat return expression in decltype of the return type? Is there a more elegant way?

like image 252
Andrey Avatar asked Aug 17 '12 12:08

Andrey


1 Answers

You're nearly there; just use decltype:

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

You could use std::result_of (Difference between std::result_of and decltype) but why bother?

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

Regarding the follow-up question: for a function

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

substituting return-type with decltype(<expression>) will usually work, but can be error prone. For example, consider:

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

Here decltype will yield std::string & and your function will return an lvalue reference to a local! This would have to be changed to:

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

In other cases, <expression> could yield a value that is not returnable for reason of being e.g. noncopyable, containing a lambda, etc.

like image 81
ecatmur Avatar answered Oct 22 '22 01:10

ecatmur