Lazy evaluation¶
Reference¶
#include <actl/functional/lazy.hpp>
-
template<Callable Function>
struct lazy¶ Wrapper to lazily evaluate a function (with no parameters) only when the result is needed.
This simple wrapper has surprisingly remarkable benefits:
Simpler and more efficient code when the function result is used conditionally, for example, when inserting an element into a map only if it doesn’t already exist:
The shortest alternative looks like this, and does an extra pass over the map:auto iter = map.try_emplace(key, ac::lazy{computeValue}).first;
auto iter = map.find(key); if (iter == map.end()) iter = map.emplace(key, computeValue()).first;
Even when the function is called unconditionally, approach similar to ac::lazy is the only way to avoid an extra move constructor when emplacing a function result into a container. If a move constructor is not defined, copy constructor is called instead.
For example, the first line here results in the extra move constructor of the result, while the second doesn’t:
std::optional optional1{computeValue()}; std::optional optional2{ac::lazy{computeValue}};
For the in-depth explanation, please refer to this article, where the analog is called
with_result_of_t(I hope you’ll find our naming better): https://quuxplusone.github.io/blog/2018/05/17/super-elider-round-2/Or to the original source of the idea: https://akrzemi1.wordpress.com/2018/05/16/rvalues-redefined/
Note
This is the simplest possible implementation, so it doesn’t perform any result caching for the case where it can be used multiple times.
See tests at tests/functional/lazy.cpp