C++ 中的记忆函子包装器

2024-03-05

这是我为函数编写的通用记忆包装器。它利用元组哈希 https://stackoverflow.com/questions/7110301/generic-hash-for-tuples-in-unordered-map-unordered-set.

template<typename R, typename... Args>
class memofunc{
    typedef R (*func)(Args...);
    func fun_;
    unordered_map<tuple<Args...>, R, tuplehash::hash<tuple<Args...> > > map_;
public:
    memofunc(func fu):fun_(fu){}
    R operator()(Args&&... args){
    auto key = make_tuple(std::forward<Args>(args)...);
    auto q = map_.find(key);
    if(q == map_.end()){
        R res = fun_(std::forward<Args>(args)...);
        map_.insert({key,res});
        return res;
    }else{
        return q->second;
    }
    }
};

斐波那契数列的用法示例。

long long fibo(long long x){
    static memofunc<long long, long long> memf(fibo);
    // try to replace fibo with this new fibo but doesn't work, why?
    // function<long long(long long)> fibo = memf; 

    if(x <= 2) return 1;
    // this works but involves changing the original code.
    // how to write code such that I dont need to manually add this code in?
    return memf(x-1) + memf(x-2); 
    // old code
    // return fibo(x-1) + fibo(x-2);
}

问题是,理想情况下我可以在递归函数的开头添加几行并完成记忆。但简单的替换是行不通的,这就是我陷入困境的地方。


您的问题似乎是您在每次函数调用时制作内存器的本地副本,然后销毁它。

这是一个简单的单参数版本的记忆器,似乎有效:

#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";
}

活生生的例子 http://ideone.com/oxLz7P

注意foo(10)仅调用 10 次foo.

这也承认:

#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);;
}

对于喜欢宏的人来说。

三步版本可能会更好。

首先,前奏是函数和记忆器包装器的前向声明。

其次,在函数内部,为函数名起一个别名,以便递归调用时使用记忆函数。

三、函数声明后,为函数名起一个别名,以便外部调用also使用记忆版本。

上面的代码只记住递归调用,而不是初始调用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ 中的记忆函子包装器 的相关文章

随机推荐

  • 如何删除pandas中每组的第一行

    我有一个像这样的数据框 id values 0 1 3 1 1 6 2 1 3 3 2 7 4 2 6 5 2 3 6 2 9 我想根据删除每组的第一行id 结果应该是这样的 id values 1 1 6 2 1 3 4 2 6 5 2
  • 使用 JS 将任何标签内的文本复制到剪贴板[重复]

    这个问题在这里已经有答案了 我需要复制 p 标签内的文本 我尝试使用以下代码 HTML p Text to copy p
  • Subversion 中的合并比 Team Foundation System 中的合并更困难吗?

    我习惯了使用TFS 我的公司现在正在为一个新项目切换到SVN 主要原因是为了更好地将我们的java和 Net代码库合并在同一源代码控制下 我被赋予理解颠覆中的合并是困难的 杰夫提到了这一点 https blog stackoverflow
  • java中的cloneable接口有什么用?

    实现可克隆接口有什么用 因为它是一个标记接口 我总是可以在我的类中创建一个公共 Object clone 方法 可克隆接口的实际用途是什么 那是因为clone 方法抛出CloneNotSupportedException如果你的对象不是Cl
  • 如何调用我们的应用程序并获取来电的详细信息?

    如果我的应用程序中保存了任何号码 并且该用户在我的 iPhone 上呼叫我 那么我想通过屏幕调用我的应用程序 用户可以在屏幕上填写有关该呼叫的信息 例如呼叫持续时间 呼叫者姓名和一些应用程序特定的详细信息 请指导我如何在 iOS 中实现通话
  • 在 C 中声明数组而不指定大小

    当像这样声明一个数组时 int array 1 2 3 4 5 6 我收到一条错误消息 数组类型具有不完整的元素类型 到底是怎么回事 对于N维数组 N gt 0 需要定义N 1维的大小 只能留下一个维度供编译器确定 并且它必须是第一个维度
  • 逐行分割字符串并进行变量化,即将其分配给 GITHUB_OUTPUT - 工作流程

    Github 行动run调用 powershell 返回如下 Powershell返回函数 return psitem Key psitem Value 返回值被分配给 github 操作变量 returnvalue 返回包含一个列表key
  • 使用自定义项目模板在组合框中显示所选项目

    我使用此页面中的代码来设计我的组合框的样式 如何在鼠标悬停时设置组合框背景的样式 https stackoverflow com a 5564151 2848002 我更改了默认项目模板 但现在它们不会出现在所选值区域中 在下图中 您可以看
  • 如何从 XML 文件中删除不可见的垃圾字符

    我想读取一些 xml 文件 当我用记事本 写字板 MS Word 或任何浏览器打开这些文件时 它以其原始形式打开 但是当我尝试用 MS DOS 执行它时 会出现一个看不见的字符 如 被看到 我认为 正在创建一个错误 我发现错误 序言中不允许
  • 防止 System.Window.Forms.ComboBox 的自动选择行为 (C#)

    背景 我有一个Forms ComboBox with a DropDownStyle DropDown 我不使用AutoComplete 但我实现了类似的东西 它不仅过滤文本的开头 而且使用正则表达式并显示与输入的文本匹配的所有项目 这很好
  • C++ - 通过指针访问向量元素的安全性

    在我的一个 C 项目中 我使用的是vector持有一堆struct包含简单游戏的许多元素 即 井字游戏 坐标 x vs o ETC IE struct gameMove int x int y int player int order 每次
  • 带微调器的叠加

    我正在尝试创建一个覆盖层 覆盖一个页面 中间有一个微调器 实现这一目标的最简单方法是什么 我只需要担心 IE 8 及以上版本 使用 css3 类 spinner 它更漂亮而且你不需要 gif spinner position absolut
  • Sweet Alert 2 在父框架中打开

    我有一个 iframe 其源是 php 文件 我想做的是让 Sweet Alert 2 在父框架中打开 而不是在 iframe 内部打开 我尝试过改变目标 但没有成功 以下目标选项均无效 swal target window target
  • 使用 Amazon SNS 使用 PHP AWS SDK v2 发送 SMS 消息?

    我继承了一个 PHP 项目 它与 AWS SDK v2 高度集成 目前无法选择使用 v3 我的问题是如何利用 SNS 根据需要向特定号码发送短信 也就是说 我不想在发生操作时向订阅特定主题的一堆电话号码发送大量通知 我想在发生操作时向特定电
  • 基于 SSL 的 Skype CDN

    我曾经测试登录用户是否可以访问 Skype CDN 来确定是否向他们显示 UI 元素 https cdn dev skype com uri skype uri js 但似乎他们的 CDN 突然移动到了这里 破坏了我的代码 http www
  • MySQL 错误代码:1175 在 MySQL Workbench 中更新期间

    我正在尝试更新专栏visited为其赋予值 1 我使用 MySQL 工作台 并在工作台内部的 SQL 编辑器中编写语句 我正在编写以下命令 UPDATE tablename SET columnname 1 它给了我以下错误 您正在使用安全
  • 如果不指定 ,如何将 传递给 IRB?

    Since irb help 用法 irb rb 选项 程序文件 参数 我知道如果我包含一个 我可以将参数传递给 ARGV程序文件 eg irb test rb A B C 其中 test irb 只是 p ARGV 产生 a b c Ma
  • 需要在java中找到最多三个数字[重复]

    这个问题在这里已经有答案了 可能的重复 在 Java 中查找不同数据类型的 3 个数字中的最大值 基本 Java https stackoverflow com questions 4982210 find the max of 3 num
  • 如何从字符串创建关键字符号? [复制]

    这个问题在这里已经有答案了 从字符串创建符号非常简单 intern test gt test 我正在努力创造keywordplist 的符号 寻找类似的东西 XXXX test gt test 注意 intern test 不产生keywo
  • C++ 中的记忆函子包装器

    这是我为函数编写的通用记忆包装器 它利用元组哈希 https stackoverflow com questions 7110301 generic hash for tuples in unordered map unordered se