0

Given the following templated function:

template <typename T>
void f(std::function <void (T)>) {}

Can I extract T without having to explicitly mention it when calling f?

f<int>([](int){}); works fine but I'd like T to be deduced and f([](int){}); to just work. The latter errors out with "no matching function for call to".

adrianton3
  • 2,258
  • 3
  • 20
  • 33
  • 1
    Why not `template void f(T const &);`? Why is `std::function` necessary? Why limit yourself to one family of callables? Not only do you create this deduction issue for yourself, you also force indirection when calling the passed functor for no good reason. – cdhowie Nov 14 '17 at 22:41
  • No you can't. Because `[](int){}` can be called with an int, a long, a char, or any number of other types for which an implicit cast operator is defined. So the "canonical" function type can't be inferred. – Silvio Mayolo Nov 14 '17 at 22:44
  • If you were dealing with a class as opposed to a function, then [deduction guides](https://stackoverflow.com/questions/40951697/what-are-template-deduction-guides-in-c17) would be your friend. – Silvio Mayolo Nov 14 '17 at 22:45

1 Answers1

2

You can deduce T if the object passed into the function actually has type std::function<void(T)>. If the type you pass in is a lambda, then you'll have to deduce it from the type of the lambda's function call operator, like so:

template <class Callable, class Arg, class T>
void f_helper(Callable callable, Ret (Callable::*)(T)) {
    // do something with T
}

template <class Callable>
void f(Callable callable) {
    f_helper(callable, &callable::operator());
}

Actually, in reality it is a bit more annoying than this, because you need at least two overloads for f_helper, according to whether the lambda is declared mutable (which determines whether operator() is const), and in C++17 you also need to double the number of overloads again according to whether the lambda is noexcept.

The standard library sidesteps issues like this by not attempting to extract the argument type from the callables you pass to algorithms such as std::sort. It just accepts an arbitrary callable type and then tries to call it.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312