8

I can write a function template:

template<typename T>
void f1(T parameter) { ... }

But in C++14, I can also create a generic lambda:

auto f2 = [](auto parameter) { ... };

Within f1 I can refer to T directly. Within f2, there's no T to refer to, but I can get the same effect using decltype:

auto f2 = [](auto parameter)
          {
            using T = decltype(param);
            ...
          };

An advantage of the generic lambda is that I can perfect-forward it. I can't do that with the function template:

template<typename T>
void fwdToG(T&& param) { g(std::forward<T>(param)); }

fwdToG(f1);        // error!
fwdToG(f2);        // okay

Are there situations where using a function template would be better than using a generic lambda?

Casey
  • 41,449
  • 7
  • 95
  • 125
KnowItAllWannabe
  • 12,972
  • 8
  • 50
  • 91

1 Answers1

4

Function templates permit overloading of other functions with the same name, and calling them works via ADL. Generic lambdas are objects with an overloaded (), so neither works.

You can pass a function overload set to an object pretty easily:

 struct foo_overload_set_t {
   template<class...Ts>
   constexpr auto operator()(Ts&&...ts)const{ return foo(std::forward<Ts>(ts)...); }
 };

which with RVO can be optimized away completely (zero overhead), and an instance of the entire overload set can be passed to an algorithm. You can also do this with a lambda at point of use, which can be generated by a macro.

With a bit more boilerplate the above overload set can also support conversion to any call-compatible function pointer, which neither the template nor lambda solution supports (lambda requires signatures match one version, not compatibility).

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • Can you give an example of what you mean by passing a function an overload set? – KnowItAllWannabe Apr 05 '14 at 03:47
  • @knowitallwannabe `std::sort(it1,it2,foo_overload_set_t{})` will do overload lookup and invoke `foo` within `std::sort`. Basically you can wrap looking up the right overload into an object which can be passed around. – Yakk - Adam Nevraumont Apr 05 '14 at 03:57
  • @knowitallwannabe Note that I did not stress the two advantages enough: overloading (outside the `class`, so distributed) and ADL (so overloading outside the namespace!) The two of them let you write code near to where it should be, instead of where the language dictates it must be. – Yakk - Adam Nevraumont Apr 06 '14 at 14:25
  • I think the overloading and ADL features are apparent in your answer, which I've upvoted. – KnowItAllWannabe Apr 06 '14 at 16:42
  • Does this imply that in general function templates should be preferred? Or are there obvious situations where a generic lamba is better (other than as a direct function argument)? – Walter Oct 23 '15 at 18:00
  • @Walter Do you want to have overloads and/or ADL, or not? Do you want to bother with the above overload set construct, or not? Does the perfect forwarding in that overload set construct cause problems, or not? – Yakk - Adam Nevraumont Oct 23 '15 at 18:09