157

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?

1
  • 12
    Why would you need the lambda by reference? Do you mean const&? Commented Jun 23, 2011 at 18:13

5 Answers 5

130

You cannot have an auto parameter. You basically have two options:

Option #1: Use std::function as you have shown.

Option #2: Use a template parameter:

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

Option #2 may, in some cases, be more efficient, as it can avoid a potential heap allocation for the embedded lambda function object, but is only possible if f can be placed in a header as a template function. It may also increase compile times and I-cache footprint, as can any template. Note that it may have no effect as well, as if the lambda function object is small enough it may be represented inline in the std::function object.

Don't forget to use std::forward<F&&>(lambda) when referring to lambda, as it is an r-value reference.

Sign up to request clarification or add additional context in comments.

11 Comments

This quote, "if the lambda function object is small enough it may be represented inline in the std::function object" is misleading. Lambdas are always available for inline (the compiler can choose not to of course). std::function implementations generally uses small object optimization to avoid heap allocations. If a lambda has a small enough capture list it will be stored in std::function without using the heap. Other than that a lambda's size has no real meaning.
@bdonlan: By the way, why is there & in void f(F & lambda)?
@bdonlan: But the const& assumes that the members of the lambda (the capture-by-values) cannot be changed. Which may not be what the user wants.
@bdonlan It's been a while, but passing as non-const reference does not allow construction of a temporary lambda in the function call. An r-value reference would be best here.
I dare to say that this has changed in C++17
|
67

I would use template as:

template<typename Functor>
void f(Functor functor)
{
   cout << functor(10) << endl;
}

int g(int x)
{
    return x * x;
}
int main() 
{
    auto lambda = [] (int x) { cout << x * 50 << endl; return x * 100; };
    f(lambda); //pass lambda
    f(g);      //pass function 
}

Output:

500
1000
100

Demo : http://www.ideone.com/EayVq

Comments

51

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

1 Comment

this is limited only to lambdas that can decay to function pointers (lambdas w/o captures), and also requires to specify exact signature (same as for std::function case though) while templated version doesn't have this limitation.
15

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) { /* ... */}

1 Comment

And as slightly mentioned, it would probably be even better to constrain F with some concepts based on the needs of f()
4

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

1 Comment

Is the only difference between the OP's code and yours being & or &&? How is this different from the "abbreviated function template", which was mentioned in @Alexey's answer? Thanks.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.