Generic way to deduce the return type of a functor?

Viewed 4085

This question is a follow-up of How to deduce the type of the functor's return value? I'm reformulating it in a more abstract way.

Given the pseudocode of a template function

template <typename Arg, typename Fn>
auto ComputeSomething(Arg arg, Fn fn) -> decltype(<decl-expr>)
{
// do something
// ............
return fn(<ret-expr>)
}

where <ret-expr> is an arbitrary expression which involves arg, what shall I use for <decl-expr> to set the return type of ComputeSomething equal to the return type of the functor.

The functor may be a class, a lambda or a function pointer.

Partial solutions I found so far.

(a) The answer for my linked question done by ecatmur. Essentially, it is repeating the return statement in <decl-expr>. Problems: it is error-prone and wouldn't work if contains local variables.

(b) It works only for function pointers

template <typename Arg, typename Ret>
Ret ComputeSomething(Arg arg, Ret(*fn)(Arg))

(c) It assumes that the argument of the functor is of type Arg (which may not hold in general) and requires Arg to be default-constructible

template <typename Arg, typename Fn>
auto ComputeSomething(Arg arg, Fn fn) -> decltype(fn(Arg())

(d) Using std::declval which is supposed to lift the default-constructible restriction, as suggested in how to deduce the return type of a function in template. Could anybody explain how it works?

template <typename Arg, typename Fn>
auto ComputeSomething(Arg arg, Fn fn) -> decltype(fn(std::declval<Arg>())
5 Answers
Related