模板函数中的静态变量看起来对模板实例不是唯一的

时间:2013-10-22 20:13:59

标签: c++ templates boost c++11 static-variables

我正在尝试使用C ++以及boost和C ++ 11规范来学习memoization。但是我遇到了一个问题,我无法绕过头脑。我在这里遵循一个教程:Memoization in C,教程说你可以使用模板和lambda函数来概括递归函数的memoization。本教程还列出了与模板一起使用的递归factorial和fibonacci函数。但是,该指南仅使用斐波那契函数。

我写了一个测试程序,看看这一切是如何工作的,并在同一次运行中同时制作一个memoized fibonacci和factorial函数。事实上,memoization模板使用静态映射来存储缓存的值,并且看起来映射对于memoized函数的每个实例都不是唯一的。这是预期的吗?我该怎么做才能使地图对每个模板实例都是唯一的?在我开始使用C ++ 11功能之前,我曾尝试创建一个模板类,它接受一个boost函数来封装这个过程。静态地图会在模板类中是唯一的吗?

创建记事本函数的主要逻辑

// Template function to create memoized versions of recursive lambda functions
template<typename inType, typename outType>
std::function<outType(inType) > memoize(std::function<outType(inType) > foo) {
   return [foo](inType n) {
      static std::map<inType, outType> memo;

      outType ret;
      if (memo.count(n) > 0) {
         cout << "Cache Hit" << endl;
         ret = memo[n];
         return ret;
      }
      ret = foo(n);
      memo[n] = ret;
      return ret;
   };
}

// Recursive lambda fibonacci function
std::function<int(int) > fibonacci_r = [](int n) {
   if (n <= 1) {
      return n;
   } else {
      return fibonacci_r(n - 1) + fibonacci_r(n - 2);
   }
};

// Recursive lambda factorial function
std::function<int(int) > factorial_r = [](int n) {
   if (n == 0) {
      return 1;
   } else {
      return n * factorial_r(n - 1);
   }
};

测试记忆功能的逻辑

int position = 7;
cout << "Fibonacci:" << endl;
cout << "Non Memo Fibonacci" << endl;
cout << position << "-> " << fibonacci_r(position) << endl;
cout << "Memo Fibonacci" << endl;
fibonacci_r = memoize(fibonacci_r);
cout << position << " -> " << fibonacci_r(position) << endl;

cout << endl;

cout << "Non Memo Factorial" << endl;
cout << position << " -> " << factorial_r(position) << endl;
cout << "Memo Factorial" << endl;
factorial_r = memoize(factorial_r);
cout << position << " -> " << factorial_r(position) << endl;

输出

Fibonacci:
Non Memo Fibonacci
7-> 13
Memo Fibonacci
Cache Hit
Cache Hit
Cache Hit
Cache Hit
Cache Hit
7 -> 13

Non Memo Factorial
7 -> 5040
Memo Factorial
Cache Hit
7 -> 13

在输出的尾端,您可以看到Memo factorial具有缓存命中。但是,我认为它不应该只有1个缓存命中。无论哪种方式,7!都不是13而13 是斐波纳契备忘录lambda下7的缓存值。

1 个答案:

答案 0 :(得分:2)

写作时

  

...似乎地图并不是每个memoized函数实例都是唯一的。这是预期的吗?

您似乎忘记了实例 wrt到static变量是基于类型,而不是基于参数的值。类型std::function<outType(inType)>在两种情况下都是相同的。显然,当只有一个实例时,您也只有一个静态map


部分解决方案可能是这样的:

template<typename inType, typename outType>
std::function<outType(inType) > memoize(std::function<outType(inType) > foo) {
   static int i = 0;
   ++i;
   return [foo](inType n) {
      static std::map<int, std::map<inType, outType>> memo;
      auto& m = memo[i];
      outType ret;
      if (m.count(n) > 0) {
         cout << "Cache Hit" << endl;
         ret = m[n];
         return ret;
      }
      ret = foo(n);
      m[n] = ret;
      return ret;
   };
}

但请注意,现在每个调用都会生成自己独立的map。如果你这样做:

auto f1 = memoize(factorial_r);
auto f2 = memoize(factorial_r);

然后f1f2共享相同的map。这也意味着如果经常这样做,最终可能会占用大量内存。