Memoization functor wrapper in c++

前端 未结 1 1480
挽巷
挽巷 2021-02-09 04:44

Here is a generic memoization wrapper I wrote for functions. It makes use of tuplehash.

template
class memofunc{
    typedef         


        
相关标签:
1条回答
  • 2021-02-09 04:53

    Your problem seems to be that you make a local copy of your memoizer at each function call, then destroy it.

    Here is a simple one-argument version of your memoizer that seems to work:

    #include <iostream>
    #include <functional>
    #include <unordered_map>
    
    template<typename Sig, typename F=Sig* >
    struct memoize_t;
    template<typename R, typename Arg, typename F>
    struct memoize_t<R(Arg), F> {
      F f;
      mutable std::unordered_map< Arg, R > results;
      template<typename... Args>
      R operator()( Args&&... args ) const {
        Arg a{ std::forward<Args>(args)... }; // in tuple version, std::tuple<...> a
        auto it = results.find(a);
        if (it != results.end())
          return it->second;
        R retval = f(a); // in tuple version, use a tuple-to-arg invoker
        results.emplace( std::forward<Arg>(a), retval ); // not sure what to do here in tuple version
        return retval;
      }
    };
    
    template<typename F>
    memoize_t<F> memoize( F* func ) {
      return {func};
    }
    
    int foo(int x) {
      static auto mem = memoize(foo);
      auto&& foo = mem;
      std::cout << "processing...\n";
      if (x <= 0) return foo(x+2)-foo(x+1); // bwahaha
      if (x <= 2) return 1;
      return foo(x-1) + foo(x-2);;
    }
    int main() {
      std::cout << foo(10) << "\n";
    }
    

    live example

    Note that foo(10) only does 10 invocations of foo.

    This also admits:

    #define CAT2(A,B,C) A##B##C
    #define CAT(A,B,C) CAT2(A,B,C)
    #define MEMOIZE(F) \
      static auto CAT( memoize_static_, __LINE__, F ) = memoize(F); \
      auto&& F = CAT( memoize_static_, __LINE__, F )
    
    int foo(int x) {
      MEMOIZE(foo);
      std::cout << "processing...\n";
      if (x <= 0) return 0;
      if (x <= 2) return 1;
      return foo(x-1) + foo(x-2);;
    }
    

    for people who like macros for this kind of thing.

    A 3 step version might be better.

    First, a prelude with a forward declaration of the function and memoizer wrapper.

    Second, within the function, an alias for the function name, so recursive calls use the memorization function.

    Third, after the declaration of the function, an alias for the function name, so external calls also use the memoized version.

    The code above only memoizes recursive calls, never the initial call.

    0 讨论(0)
提交回复
热议问题