#include <Corrade/Containers/Function.h>
template<class R, class ... Args>
Function<R(Args...)> class new in Git master
Function wrapper.
An alternative to std::
Containers::Function<int(int)> a = std::abs; Containers::Function<int(int)> b = [](int value) { return value*2; }; struct Accumulator { int sum = 1337; int add(int value) { return sum += value; } } accumulator; Containers::Function<int(int)> c{accumulator, &Accumulator::add};
The wrapped function is then called through operator()():
a(-16); // 16 b(376); // 752 c(110); // 1447
To prevent accidental type conversions and potential extra overhead coming from those, the wrapper only accepts functions that match the signature exactly. If a function or a functor has a set of overloads (such as is the case with std::
double degreesToRadians(double); //Containers::Function<float(float)> a = degreesToRadians; // error Containers::Function<float(float)> b = [](float radians) -> float { return float(degreesToRadians(double(radians))); };
Function call overhead
On construction, a stateless wrapper lambda is created that then delegates to the particular free function pointer, member function pointer, or a stateful functor / lambda. In the common case this means that invoking a Function always involves two function calls, one for the wrapper lambda and one for the actual function being called.
If the wrapped function is inlineable, in optimized builds this can reduce to just a single function call to the wrapper lambda, which then has the actual function call inlined inside.
Stateful function storage
The Function class is internally made large enough to fit any free or member function pointer. But because member function pointers can increase in size if multiple inheritance and/or virtual inheritance is involved, that space can be repurposed also for saving up to 24 bytes of stateful lambda / functor data on 64-bit platforms (and up to 16 bytes on 32-bit platforms). If larger, the data is allocated on heap instead. For implementation simplicity reasons the state is also allocated if isn't trivially copyable. You can use isAllocated() to check whether the function state needed a heap allocation or not.
/* Small enough, stored inline */ int seed = …; Containers::Function<int(int)> hash = [seed](int value) { return seed ^ value; }; /* Too large, allocated */ int state[8]{…}; Containers::Function<int()> random = [state]() mutable { … }; /* Small enough but non-trivial, allocated */ Containers::String salt = …; Containers::Function<int(int)> checksum = [salt](int value) { … };
If heap allocation is undesirable, the Function(NoAllocateInitT, F&&) overload can be used to prevent wrapping any function with state that would need to be allocated:
Containers::Function<int(int)> hash{Containers::NoAllocateInit, [seed](int value) { … }}; // Containers::Function<int()> random{Containers::NoAllocateInit, // error // [state]() mutable { … }};
Type-erased function storage
The class derives from a type-erased FunctionData base, which owns all state and also takes care of proper moving and destruction for non-trivial functors. This allows it to be used as a type-erased storage in various containers for example. Cast the instance back to a concrete Function in order to use it.
Containers::FunctionData a = Containers::Function<int(int)>{std::abs}; Containers::FunctionData b = Containers::Function<float(float)>{std::round}; static_cast<Containers::Function<int(int)>&>(a)(-15); // 15 static_cast<Containers::Function<float(float)>&>(b)(3.56f); // 4.0f
Base classes
- class FunctionData new in Git master
- Function data storage
Public types
- using Type = R()(Args...)
- Function type.
Constructors, destructors, conversion operators
-
Function(std::
nullptr_t = nullptr) noexcept - Default constructor.
- Function(R(*)(Args...) f) noexcept
- Wrap a free function pointer.
-
template<class Instance, class Class>Function(Instance& instance, R(Class::*)(Args...) f) noexcept
- Wrap a member function pointer.
-
template<class Instance, class Class>Function(Instance& instance, R(Class::*)(Args...) f&) noexcept
-
template<class Instance, class Class>Function(Instance& instance, R(Class::*)(Args...) const f) noexcept
-
template<class Instance, class Class>Function(Instance& instance, R(Class::*)(Args...) const f&) noexcept
-
template<class Instance>Function(Instance&, std::
nullptr_t) noexcept - Create a null member function pointer.
-
template<class F>Function(F&& f) noexcept(…)
- Wrap a lambda or a functor.
-
template<class F>Function(NoAllocateInitT, F&& f) explicit noexcept
- Wrap a small enough and trivial lambda / functor.
Public functions
- auto operator()(Args... args) -> R
- Call the function pointer.
Function documentation
template<class R, class ... Args>
Corrade:: Containers:: Function<R(Args...)><R, Args>:: Function(std:: nullptr_t = nullptr) noexcept
Default constructor.
Creates a nullptr
function.
template<class R, class ... Args>
Corrade:: Containers:: Function<R(Args...)><R, Args>:: Function(R(*)(Args...) f) noexcept
Wrap a free function pointer.
If f
is nullptr
, the constructor is equivalent to Function(std::
template<class R, class ... Args>
template<class Instance, class Class>
Corrade:: Containers:: Function<R(Args...)><R, Args>:: Function(Instance& instance,
R(Class::*)(Args...) f) noexcept
Wrap a member function pointer.
Default, &
, const
and const &
r-value overloads are supported, &&
and const &&
however isn't, as the member function is always called on a l-value. If f
is nullptr
, the constructor is equivalent to Function(std::
template<class R, class ... Args>
template<class Instance, class Class>
Corrade:: Containers:: Function<R(Args...)><R, Args>:: Function(Instance& instance,
R(Class::*)(Args...) f&) noexcept
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
template<class R, class ... Args>
template<class Instance, class Class>
Corrade:: Containers:: Function<R(Args...)><R, Args>:: Function(Instance& instance,
R(Class::*)(Args...) const f) noexcept
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
template<class R, class ... Args>
template<class Instance, class Class>
Corrade:: Containers:: Function<R(Args...)><R, Args>:: Function(Instance& instance,
R(Class::*)(Args...) const f&) noexcept
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
template<class R, class ... Args>
template<class Instance>
Corrade:: Containers:: Function<R(Args...)><R, Args>:: Function(Instance&,
std:: nullptr_t) noexcept
Create a null member function pointer.
Equivalent to Function(std::
template<class R, class ... Args>
template<class F>
Corrade:: Containers:: Function<R(Args...)><R, Args>:: Function(F&& f) noexcept(…)
Wrap a lambda or a functor.
The functor is expected to exactly match the signature, no implicit conversions on either the arguments or return type are allowed. If the lambda capture or functor state is small enough and trivially copyable, it's stored inline, otherwise allocated on heap. See Stateful function storage for more information.
template<class R, class ... Args>
template<class F>
Corrade:: Containers:: Function<R(Args...)><R, Args>:: Function(NoAllocateInitT,
F&& f) explicit noexcept
Wrap a small enough and trivial lambda / functor.
Compared to Function(F&&) compiles only if the lambda capture or functor state is small enough and trivially copyable to not need to be allocated on heap. See Stateful function storage for more information.
Note that there's no NoAllocateInit variant for free or member function pointers, as they never need to be allocated on heap.
template<class R, class ... Args>
R Corrade:: Containers:: Function<R(Args...)><R, Args>:: operator()(Args... args)
Call the function pointer.
Expects that the pointer is not nullptr
.