skip to Main Content

Understanding Lambda Expressions

In some cases, you may need to create a useful piece of code, which will be used just once. That moment, you might find yourself thinking about creating a function for that (which, in this particular case, will only get called once) and I imagine that while you’re thinking that you might be cringing (at least I would). Consider the following example:

You need to destroy an Actor after let’s say 5 seconds . Well that’s easy huh? You will just enable a timer and call the function Destroy() after 5 seconds using the following block of code:

However, when you do compile your code the following error occurs:

error

This happens because the above block of code is valid when the function you provided has a void return type and no parameters. The Destroy function has a bool return type so that’s why you get the compile error.

Then you find yourself thinking “That’s ok, I will just use a TimerDelegate and use a different overload of the SetTimer function”. Let’s see how this turns out. Consider the following code:

Ok, this code will compile just fine, however….when the time comes and the TimerManager will try to execute your bound function this is the result:

error1

Ok…now I’m kinda frustrated. “I will just create the following wrapper function and get it over with:”

If you resorted to such a solution this might happen again and again until you have more useless functions that you can count. Let’s see the easy solutions for this kind of problem!

Lambda Expressions

A Lambda expression is an anonymous function which does something useful*. You will find yourself using lambdas in cases similar to the one I described above. You need to create a functionality that will get called once and you don’t really need to name them.

*This means that you can’t use a lambda with the same way you use a function(ie this->DoSomething()).

Before we jump in and write our first lambdas, let’s breakdown their syntax first. A Lambda expression is defined using the following syntax:

[ ]( ) { //code goes here }

Ok.. wait what? What is this? Don’t worry! Everything will be clear in the following lines – so keep on reading! Lambdas (in this post at least) are divided into three “sections” (they are not really sections, I just used this word to better describe them)

  1. The Capture List: which is the [ ]
  2. The Argument List: which is the ( )
  3. And the Function Body which is enclosed in { }

Capture List

The capture list defines what from the outside of the lambda should be available inside your function body and how. For example, the capture list can be either:

  • A Reference of a variable or instance or whatever you want: [&] (This means that we passed as a reference the whole object which the lambda resides in)
  • A value: [x] (This means that we passed the variable x by value)
  • Any combination of the above

For example, the following capture list contains a reference of the current object and a value of the x variable: [&this, x]

Argument List

The argument list is exactly the same as the argument list of your “ordinary” functions. For example: (int n)

Function Body

The function body contains the logic of our function

Writing our first Lambda Expression

Let’s go back to the problem introduced in the intro section of the post. I will recap just in case you forgot: We need to destroy an Actor after 5 seconds however everything we’ve tried has not worked. The workaround is pretty simple (and slick!). We’ll just use a lambda expression:

I hope you have noticed the “&” inside the capture list. I passed as reference the whole object in order to have access to it’s Destroy function. If you ommit the “&” symbol your code won’t compile because the compiler will not be able to access the function you need in this case.

I created a C++ class which inherits from Actor and typed the above code right after the Super::BeginPlay. Then, created a blueprint based on my class and placed in on my level. The output after 5 seconds is:

output

Wow! That’s cool, right!? We got away from declaring and typing logic for a function that is going to be used only once!

Let’s create more lambdas just to demonstrate their usage and better understand the capture list!

Lambda with parameters

In the following example, I want to have an Array with all my actors in the current level. Then, I will choose a random one by index and print out its’ name.

To do this, I created a First Person Blueprint Project and added a C++ class which inherits from the Actor class. After that, I’ve modified my BeginPlay function:

After creating  a Blueprint and placing it inside my level here is my output:

output2

Please note that your output might differ since this example depends on your map!

Avatar photo

This Post Has 8 Comments

  1. Usefull tutorial (as usual), i have a question about Lambda with parameters, i was look into the implementation of UHierarchicalInstancedStaticMeshComponent::GetInstancesOverlappingSphere and i found this:

    [Sphere, StaticMeshBoundsRadius](const FMatrix& InstanceTransform)->bool
    {
    FSphere InstanceSphere(InstanceTransform.GetOrigin(), StaticMeshBoundsRadius * InstanceTransform.GetScaleVector().GetMax());
    return Sphere.Intersects(InstanceSphere);
    }

    can you explain me why the parameter have a “->bool” at the end? Is To dynamically deduce return type like this example?

    auto add(int a, int b) -> int
    {
    return a+b;
    }

    1. Hey Yuri,

      Most of the times the compiler is smart enough to understand the return type of the written lambda expression. However, when things get complex, you have to specify the return type of your lambda.

      The GetInstancedOverlappingSphere function calls the GatherInstancesOverlappingArea function (located in line 2800 in the HierarchicalInstancedStaticMesh.cpp) which takes a TFunctionRef (I’m assuming this is wrapper function – similar to TBaseDelegate(s) which are used throughout the engine) that has a bool return type and a const FMatrix& as a parameter. Since things get quite complex you have to explicitly specify that your return type is bool, otherwise the compiler won’t be able to understand what you’re typing and therefore, won’t compile.

      -Orfeas

    1. That is because FTimerHandler works only with functions, that do not return or take any arguments
      In case of Destroy, it is returning a bool. But timer was looking for smthing like void Destroy();

  2. Hey, great tutorial. I have been using lambdas to simplify delays in c++ code for a while now , it really makes codes shorter and more straigthforward. However I have noticed recently an issue with this approach: if the World changes and such a timer is active, the game crashes.

    For example, if you start a delay for a lambda function using the procedure described above (binding a lambda to a FTimerDelegate), and before the timer ends you change map, the game will crash, this has happened a couple times to me and the log always points to the function that would have been called.

    Has this problem happened to you, and if so, do you know a way to counter it?

    Just to give more info, the way I’ve implemented delays in my projects is, I’ve made a class callled FDelay with a pubic static method that takes a float (the delay) and a TFunction (a lambda).

    FDellay::Call(const UObject* WorldContextObject, float Delay, TFunction Lambda)
    {
    UWorld* World = WorldContextObject->GetWorld();
    FTimerHandle TimerHandle;
    FTimerDelegate TimerDelegate;
    TimerDelegate.BindLambda(Lambda);

    World->GetTimerManager().SetTimer(TimerHandle, TimerDelegate, Delay, false);
    }

    And any class can use the delay like this:

    AMyClass::SomeFunction()
    {
    // do some stuff immediately

    FDelay::Call(this, 1.0f, [&]()
    {
    // do some stuff after 1 second with this lambda
    });
    }

Leave a Reply to Nihal Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Back To Top