Just for fun, here is a small general memoizer that I wrote some time ago. Naturally, this requires variation patterns:
template <template <typename...> class Container, typename...> struct Memo; template <typename R, typename... Args, template <typename...> class Container> struct Memo<Container, R, std::tuple<Args...>> { Memo(std::function<R(Args...)> f) : func(f) { } R operator()(Args && ...args) { const auto arg = std::make_tuple(args...); typename CacheContainer::const_iterator it = cache.find(arg); if (it == cache.cend()) { it = cache.insert(typename CacheContainer::value_type(arg, func(std::forward<Args>(args)...))).first; std::cout << "New call, memoizing..." << std::endl; } else { std::cout << "Found it in the cache!" << std::endl; } return it->second; } private: typedef Container<typename std::tuple<Args...>, R> CacheContainer; std::function<R(Args...)> func; CacheContainer cache; }; template <typename R, typename... Args> Memo<std::map, R, std::tuple<Args...>> OMapMemoize(R(&f)(Args...)) { return Memo<std::map, R, std::tuple<Args...>>(f); } template <typename R, typename... Args> Memo<std::unordered_map, R, std::tuple<Args...>> UMapMemoize(R(&f)(Args...)) { return Memo<std::unordered_map, R, std::tuple<Args...>>(f); }
Iβm not quite sure whether I got the legal veracity correctly, as I wrote this a long time ago. Anyway, here is a test case:
int foo(double, char) { return 5; } int main() { auto f = OMapMemoize(foo); auto g = UMapMemoize(foo); int a, b; a = f(1.0, 'a'); a = f(1.0, 'a'); a = f(1.0, 'a'); a = f(1.0, 'a'); b = g(1.0, 'a'); b = g(1.0, 'a'); b = g(1.0, 'a'); b = g(1.0, 'a'); return a; }
Kerrek SB Mar 15 2018-12-15T00: 00Z
source share