Since the cache must be shared between function calls, you need to either pass it as an argument, or share it differently. One way to share it is to use a function object:
struct fib { std::map<std::tuple<int>, int> cache; int operator()(int n) { if(n < 2) return n; auto memoize = [this](int p) { auto i = cache.find(p); if(i == cache.end()) i = cache.insert({p, (*this)(p)}).first; return i->second; }; return memoize(n-1) + memoize(n-2); } };
Where you can measure the memoize part.
There is also a trick with a temporary lifetime for passing memoized functions as an argument; something like that:
struct recurse // possibly a class template { std::function<int(int, recurse const&)> f; // possibly `mutable` template<class T> recurse(T&& p) : f( memoize(decltype(f){p}) ) {} int operator()(int x) const { return f(x, *this); } }; int fib(int n, recurse const& f); int fib(int n, recurse const& f = {fib}) { if(n < 2) return n; return f(n-1) + f(n-2); // or `fib(n-1, f) + fib(n-2, f)` }
However, this requires a change to memoize , because recurse const& cannot (and should not) be part of the internal map .
<sub> NB those const& can also be && to extend longevity, however, this can be confusing due to the semantics of movement
source share