Proper way to receive a lambda as parameter by reference

Viewed 122374

What is the right way to define a function that receives a int->int lambda parameter by reference?

void f(std::function< int(int) >& lambda);

or

void f(auto& lambda);

I'm not sure the last form is even legal syntax.

Are there other ways to define a lambda parameter?

5 Answers

I know it's been 7 years, but here's a way nobody else mentioned:

void foo(void (*f)(int)){
    std::cout<<"foo"<<std::endl;
    f(1); // calls lambda which takes an int and returns void
}
int main(){
    foo([](int a){std::cout<<"lambda "<<a<<std::endl;});
}

Which outputs:

foo
lambda 1

No need for templates or std::function

Since C++ 20,

void f(auto& lambda);

actually works (it's an abbreviated function template):

When placeholder types (either auto or Concept auto) appear in the parameter list of a function declaration or of a function template declaration, the declaration declares a function template, and one invented template parameter for each placeholder is appended to the template parameter list

and it's equivalent to exactly option 2 in @bdonlan's answer:

template<typename F>
void f(F &lambda) { /* ... */}

void f(auto& lambda);

That's close. What will actually compile is:

#include <cassert>

/*constexpr optional*/ const auto f = [](auto &&lambda)
{
  lambda();
  lambda();
};

int main()
{
  int counter = 0;
  f([&]{ ++counter; });
  assert(counter == 2);
}
Related