|
Orrery
A GPU-accelerated N-body gravitational simulator
|
A non-owning reference to something callable. More...
#include <functional>#include <memory>#include <type_traits>#include <utility>Go to the source code of this file.
Classes | |
| class | orrery::core::FunctionRef< Result(Args...)> |
| A reference to a callable taking Args and returning Result. More... | |
A non-owning reference to something callable.
The scheduler in backend/ has to hand a piece of work to a thread it did not compile against. The work is a lambda closing over whatever the caller happened to have to hand, the scheduler is a virtual interface chosen at run time, and a virtual function cannot be a template, so the closure has to be erased behind a uniform type at that boundary.
std::function is the usual answer and is the wrong one here. It owns what it holds, so constructing one from a closure that captures four spans may allocate, and the boundary it would sit on is crossed once per force evaluation: several times per timestep, for the whole length of a run. The ownership buys nothing, because the closure provably outlives the call. It is a local in the caller's frame and the callee returns before the caller does.
This is the type the standard adopted for the same reason, as std::function_ref in C++26. The project is on C++20, so it is written here rather than waited for, and it can be deleted when the compilers catch up.
The cost of not owning is the usual one, and it is real: a FunctionRef outliving the callable it refers to is a dangling pointer with no diagnostic. It is safe in the one shape this project uses it in, an argument to a call that returns before the full expression ends, and it should not be stored in a member or returned from a function.