49

I would like to use a lambda as a parameter for a C++ function, but I don't know which type to specify in the function declaration. What I would like to do is this:

void myFunction(WhatToPutHere lambda){
    //some things
}

I have tried void myFunction(auto lambda) and void myFunction(void lambda) but none of these codes compiled. In case it matters, the lambda doesn't return anything.

How can I use a lambda as a parameter in a C++ function?

Donald Duck
  • 8,409
  • 22
  • 75
  • 99

4 Answers4

47

You have 2 ways: make your function template:

template <typename F>
void myFunction(F&& lambda)
{
    //some things
}

or erase type (with std::function for example):

void
myFunction(const std::function<void()/*type of your lamdba::operator()*/>& f)
{
    //some things
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • 5
    Note that the former generates a new clone of your function per each different lambda that you pass to it throughout your program, and can't easily be used (probably not at all) for functions that you want to define in a separate compilation unit. – The Vee Nov 28 '16 at 12:59
  • 18
    Note that the second solution will induce quite some runtime overhead and will do dynamic allocation. As the first solution is as fast as if you put the content on the lambda inside `myFunction` – Guillaume Racicot Nov 28 '16 at 15:06
  • How should I implement the function in a separate file (cpp) for the first version? – X.Arthur Jul 01 '21 at 12:47
  • @X.Arthur: You cannot. – Jarod42 Jul 01 '21 at 12:49
  • @Jarod42 You mean I cannot do explicit instantiation in a cpp file similar to what can be done for normal types? – X.Arthur Jul 01 '21 at 12:52
  • @X.Arthur: Lambda types are unnamed, so hard to provide explicit instantiation with them. Creating several `myFunction`A-Z declaration, and putting definition in cpp which forward to the template with appropriate lambda would be possible. – Jarod42 Jul 01 '21 at 12:55
27

You have two choices, basically.

Make it a template:

template<typename T>
void myFunction(T&& lambda){
}

or, if you do not want (or can't) do that, you can use type-erased std::function:

void myFunction(std::function<void()> const& lambda){
}

Conversely, your attempt with auto would've been correct under the concepts TS as currently implemented in gcc, where it'd be an abbreviated template.

// hypothetical C++2x code
void myFunction(auto&& lambda){
}

or with a concept:

// hypothetical C++2x code
void myFunction(Callable&& lambda){
}
krzaq
  • 16,240
  • 4
  • 46
  • 61
  • For the template version, what's the advantange over void myFunction(T& lambda) or void myFunction(const T& lambda) ? – BruceSun Jul 06 '22 at 03:48
  • 1
    The usual forwarding reference advantage: you don't have to implement the function for const and non-const overloads if you aim to support non-const `operator()`. That being said, most, if not all, of the stdlib algorithms take the function object by copy, so maybe there's no reason to account for this case in general. – krzaq Jul 07 '22 at 01:39
4

Pass it as you'd pass a simple function. Just give it a name with auto

#include <iostream>

int SimpleFunc(int x) { return x + 100; }
int UsingFunc(int x, int(*ptr)(int)) { return ptr(x); }
auto lambda = [](int jo) { return jo + 10; };

int main() {
    std::cout << "Simple function passed by a pointer: " << UsingFunc(5, SimpleFunc) << std::endl;
    std::cout << "Lambda function passed by a pointer: " << UsingFunc(5, lambda) << std::endl;

}

Output:
Simple function passed by a pointer: 105
Lambda function passed by a pointer: 15

Mykola Tetiuk
  • 153
  • 1
  • 13
3

If this is an inline function, prefer a template, as in

template<typename Func>
void myFunction(Func const&lambda)
{
    //some things
}

because it binds to anything that makes sense (and will cause compiler error for anything else), including lambdas, instances of named classes, and std::function<> objects.

On the other hand, if this function is not inline, i.e. implemented in some compilation unit, you cannot use a generic template but must use a specified type, which is best taken a std::function<> object and passed via reference.

Walter
  • 44,150
  • 20
  • 113
  • 196