Looking for a way to implement a universal generic memoization function which will take a function and return the memoized version of the same?
Looking for something like @memo (from Norving's site)decorator in python.
def memo(f):
table = {}
def fmemo(*args):
if args not in table:
table[args] = f(*args)
return table[args]
fmemo.memo = table
return fmemo
Going more general, is there a way to express generic and reusable decorators in C++, possibly using the new features of C++11?
The right way to do memoization in C++ is to mix the Y-combinator in.
Your base function needs a modification. Instead of calling itself directly, it takes a templateized reference to itself as its first argument (or, a
std::function<Same_Signature>
recursion as its first argument).We start with a Y-combinator. Then we add in a cache on the
operator()
and rename it tomemoizer
, and give it a fixed signature (for the table).The only thing left is to write a
tuple_hash<template<class...>class Hash>
that does a hash on a tuple.The type of the function that can be memoized is
(((Args...)->R), Args...) -> R
, which makes the memoizer of type( (((Args...) -> R), Args...) -> R ) -> ((Args...) -> R)
. Having a Y-combinator around to produce a 'traditional' recursive implementation can also be useful.Note that if the function memoized modifies its args during a call, the memoizer will cache the results in the wrong spot.
live example with a hard-coded hash function based off this SO post.
I struggled with the same problem. I created macro that also support (with small modification in recursive code) recursion. Here it is:
The usage is really simple:
See it in action: http://ideone.com/C3JEUT :)
A compact one returning a lambda:
In C++14, one can use generalized return type deduction to avoid the extra indirection imposed by returning
std::function
.Making this fully general, permitting passing arbitrary function objects without wrapping them in
std::function
first is left as an exercise for the reader.Although @KerrekSB posted a link to another answer, I though I'd throw my answer in the ring as well (it's probably slightly less complicated than the linked answer, although in essence it's very similar):
Edit: Example usage:
Edit2: As pointed out, this doesn't work with recursive functions.