Blender  V3.3
Classes | Namespaces
BLI_function_ref.hh File Reference
#include <optional>
#include <type_traits>
#include <utility>
#include "BLI_utildefines.h"
#include "BLI_memory_utils.hh"

Go to the source code of this file.

Classes

class  blender::FunctionRef< Ret(Params...)>
 

Namespaces

 blender
 

Detailed Description

A FunctionRef<Signature> is a non-owning reference to some callable object with a specific signature. It can be used to pass some callback to another function.

A FunctionRef is small and cheap to copy. Therefore it should generally be passed by value.

Example signatures: FunctionRef<void()> - A function without parameters and void return type. FunctionRef<int(float)> - A function with a float parameter and an int return value. FunctionRef<int(int, int)> - A function with two int parameters and an int return value.

There are multiple ways to achieve that, so here is a comparison of the different approaches:

  1. Pass function pointer and user data (as void *) separately:
    • The only method that is compatible with C interfaces.
    • Is cumbersome to work with in many cases, because one has to keep track of two parameters.
    • Not type safe at all, because of the void pointer.
    • It requires workarounds when one wants to pass a lambda into a function.
  2. Using std::function:
    • It works well with most callables and is easy to use.
    • Owns the callable, so it can be returned from a function more safely than other methods.
    • Requires that the callable is copyable.
    • Requires an allocation when the callable is too large (typically > 16 bytes).
  3. Using a template for the callable type:
    • Most efficient solution at runtime, because compiler knows the exact callable at the place where it is called.
    • Works well with all callables.
    • Requires the function to be in a header file.
    • It's difficult to constrain the signature of the function.
  4. Using FunctionRef:
    • Second most efficient solution at runtime.
    • It's easy to constrain the signature of the callable.
    • Does not require the function to be in a header file.
    • Works well with all callables.
    • It's a non-owning reference, so it cannot be stored safely in general.

The fact that this is a non-owning reference makes FunctionRef very well suited for some use cases, but one has to be a bit more careful when using it to make sure that the referenced callable is not destructed.

In particular, one must not construct a FunctionRef variable from a lambda directly as shown below. This is because the lambda object goes out of scope after the line finished executing and will be destructed. Calling the reference afterwards invokes undefined behavior.

Don't: FunctionRef<int()> ref = []() { return 0; }; Do: auto f = []() { return 0; }; FuntionRef<int()> ref = f;

It is fine to pass a lambda directly to a function:

void some_function(FunctionRef<int()> f); some_function([]() { return 0; });

Definition in file BLI_function_ref.hh.