c++怎么实现一个类型擦除(Type Erasure)的函数包装器_C++泛型编程与类型擦除技巧


类型擦除通过基类虚函数统一接口,模板派生类保存具体可调用对象,包装器持基类指针实现值语义,支持任意可调用类型但隐藏具体类型,如简易std::function实现所示。

c++怎么实现一个类型擦除(type erasure)的函数包装器_c++泛型编程与类型擦除技巧

类型擦除(Type Erasure)是一种让不同类型共享统一接口的技术,常用于实现类似 std::function 的泛型函数包装器。它能隐藏具体类型信息,只暴露行为接口,从而实现运行时多态而无需继承体系。

基本思路:封装可调用对象

目标是实现一个通用的函数包装器,支持任意可调用类型(函数指针、lambda、仿函数等),但对外呈现统一类型。核心是把“具体类型”擦除,只保留“调用能力”。

我们通过以下组件实现:

  • 基类接口:定义调用操作的虚函数
  • 模板派生类:保存具体可调用对象
  • 包装器类:持有基类指针,提供值语义

手动实现简易 std::function

下面是一个简化版的函数包装器,支持无参返回 int 的调用:

#include <memory>
#include <iostream>

class Function {
  struct CallableBase {
    virtual ~CallableBase() = default;
    virtual int call() = 0;
    virtual std::unique_ptr<CallableBase> clone() const = 0;
  };

  template <typename F>
  struct CallableModel : CallableBase {
    F func;
    explicit CallableModel(F f) : func(std::move(f)) {}

    int call() override { return func(); }

    std::unique_ptr<CallableBase> clone() const override {
      return std::make_unique<CallableModel>(func);
    }
  };

  std::unique_ptr<CallableBase> callable;

public:
  Function() = default;

  template <typename F>
  Function(F f) : callable(std::make_unique<CallableModel<F>>(std::move(f))) {}

  Function(const Function& other)
    : callable(other.callable ? other.callable->clone() : nullptr) {}

  Function& operator=(const Function& other) {
    if (this != &other) {
      callable = other.callable ? other.callable->clone() : nullptr;
    }
    return *this;
  }

  Function(Function&&) = default;
  Function& operator=(Function&&) = default;

  int operator()() const {
    if (!callable) throw std::bad_function_call();
    return callable->call();
  }

  explicit operator bool() const { return !!callable; }
};

使用示例:

无限画 无限画

千库网旗下AI绘画创作平台

无限画 574 查看详情 无限画
int foo() { return 42; }

int main() {
  Function f1 = []{ return 100; };
  Function f2 = foo;

  std::cout << f1() << "\n"; // 输出 100
  std::cout << f2() << "\n"; // 输出 42

  Function f3 = f1;
  std::cout << f3() << "\n"; // 输出 100
}

支持任意签名和参数

要支持不同函数签名,可将 Function 改为模板:

template <typename Signature>
class Function;

template <typename R, typename... Args>
class Function<R(Args...)> {
  struct CallableBase {
    virtual ~CallableBase() = default;
    virtual R call(Args... args) = 0;
    virtual std::unique_ptr<CallableBase> clone() const = 0;
  };

  template <typename F>
  struct CallableModel : CallableBase {
    F func;
    explicit CallableModel(F f) : func(std::move(f)) {}

    R call(Args... args) override { return func(std::forward<Args>(args)...); }

    std::unique_ptr<CallableBase> clone() const override {
      return std::make_unique<CallableModel>(func);
    }
  };

  std::unique_ptr<CallableBase> callable;

public:
  Function() = default;

  template <typename F>
  Function(F f) : callable(std::make_unique<CallableModel<F>>(std::move(f))) {}

  Function(const Function& other)
    : callable(other.callable ? other.callable->clone() : nullptr) {}

  Function& operator=(const Function& other) {
    if (this != &other) {
      callable = other.callable ? other.callable->clone() : nullptr;
    }
    return *this;
  }

  Function(Function&&) = default;
  Function& operator=(Function&&) = default;

  R operator()(Args... args) const {
    if (!callable) throw std::bad_function_call();
    return callable->call(std::forward<Args>(args)...);
  }

  explicit operator bool() const { return !!callable; }
};

性能与优化考虑

上述实现每次调用都有虚函数开销。实际如 std::function 会结合小对象优化(Small Buffer Optimization),在栈上存储小型可调用对象,避免堆分配。

关键点:

  • 类型擦除牺牲部分性能换取接口统一
  • 避免频繁拷贝包装器,尤其含大闭包的 lambda
  • 注意异常安全和资源管理(使用智能指针)

基本上就这些。不复杂但容易忽略细节,比如正确实现拷贝语义和所有权转移。

以上就是c++++怎么实现一个类型擦除(Type Erasure)的函数包装器_C++泛型编程与类型擦除技巧的详细内容,更多请关注其它相关文章!


# ai  # 可靠网站建设费用怎么算  # 海外营销推广服务的特点  # 都有  # 是一个  # 判断是否  # 管理机制  # 与非  # 有什么区别  # 多态  # 遍历  # 擦除  # 递归  # stream  # ios  # c++  # 栈  # 膏药推广营销方案策划  # 蜂鸟seo是什么原理  # 常熟网站优化咨询公司  # 北京智能化营销推广操作  # 滨州个人网站优化  # 房地产营销推广费用税率  # 西城区推广网络营销收费  # seo目录优化网站 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 优化推广96088 】 【 技术知识133117 】 【 IDC资讯59369 】 【 网络运营7196 】 【 IT资讯61894 】


相关推荐: 优化 React onClick 事件处理:函数引用与箭头函数的对比  Golang如何使用gRPC拦截器实现日志收集_Golang gRPC拦截器日志收集实践  以下哪一个是适应长期护理制度发展而设立的新职业  《书耽》更换手机号方法  重返未来:1999卡戎全方位攻略  VS Code快捷键when上下文子句的妙用  AO3中文入口稳定分享_AO3官网HTTPS看文详解  教资成绩怎么查询  HTML Canvas文本样式定制指南:解决外部字体加载与应用难题  byrutor直接访问入口 byrutor官方游戏库  163邮箱网页版入口 163邮箱在线使用  SQLAlchemy 2.0 与 Pydantic 模型类型安全集成指南  mysql中外键约束如何使用_mysql FOREIGN KEY操作  iQOO手机信号差网络不稳定怎么办 信号问题原因排查与增强设置【攻略】  在J*a里什么是行为抽象_抽象行为对代码复用的提升作用  空腹吃苹果好吗 苹果空腹摄入指南  实现二叉树的层序插入:基于树大小的路径导航  J*aScript桌面应用_Electron多进程架构实战  免费占卜在线神算_免费占卜手机神算  虫虫漫画排行榜单入口_虫虫漫画编辑推荐入口  使用 .htaccess 正确配置 WordPress 子目录重定向与路径保留  Linux如何优化系统启动流程_Linux启动项优化方案  win11讲述人怎么关闭 Win11屏幕朗读辅助功能禁用方法【技巧】  手机雨课堂网页版入口免登录 雨课堂网页版可点击直接进入  行者app怎样导出日志  msn官方入口2025登录 msn官网2025直达首页入口  《三国:谋定天下》平民全阶段通用阵容  猫眼电影app如何设置电影上映提醒_猫眼电影上映提醒设置教程  创建您的便携版VS Code:让配置随身携带  Python自动化抓取GBGB赛狗比赛结果:日期范围与赛道筛选教程  可米酷漫画在线阅读入口_ 可米酷漫画官网直达链接  Teambition网盘如何共享文件  《sketchbook》选中部分图案移动方法  餐馆菜篮选购指南  Composer如何使用composer-plugin-api开发自定义插件  《华夏千秋》龙女试炼功法获取方法  智慧职教mooc平台登录网址 智慧职教mooc官网直达  店铺如何关联视频号推广?视频号推广有什么用?  圆通快递官方入口不需要登录 在线查询入口快速查询  《小黑盒》删除历史浏览方法  店铺如何做视频号推广?做视频号推广有用吗?  word表格如何按某一列内容进行排序_Word表格按列排序方法  喜茶GO更换登录账号方法  之了课堂app做题入口  sublime怎么在文件中显示代码结构大纲_sublime符号列表功能  易车网官网直达入口 易车网在线登录入口  掌握Go App Engine项目结构与GOPATH:包管理与导入实践  虫虫助手如何更新游戏  鸣潮历史学家灯塔位置一览  电子白板帮助菜单使用指南 

 2025-11-17

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

运城市盐湖区信雨科技有限公司


运城市盐湖区信雨科技有限公司

运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。

 8156699

 13765294890

 8156699@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.