发布 Proxy 4:C++ 多态的下一次飞跃

微软技术分享
优质创作者: 编程框架技术领域
领域专家: 操作系统技术领域
2026-04-07 11:01:41

Proxy 4 版本已正式发布!经过多年的创新,且自 2022 年起便在 Windows 操作系统代码库中持续投入使用,Proxy 已从一项大胆的实验,成熟为一款面向运行时多态性的生产级现代 C++ 库。Proxy 背后的理论具有原创性,其设计也已在大规模场景中得到验证。我们非常高兴能邀请广大 C++ 社区与我们一同塑造多态性的未来。你的想法与贡献,比以往任何时候都更受欢迎!

特别感谢 @SidneyCogdill 做出的杰出贡献,尤其是为 Proxy 带来了对 C++20 模块的支持,并推动了主版本兼容性相关工作。他的付出让这个库变得更易于使用,也更具前瞻性。

什么是 Proxy?

Proxy 是一个仅头文件、跨平台的 C++20 库,它让你能够编写多态代码,却无需承受继承带来的麻烦,也不必受传统虚函数的限制。借助 Proxy,你可以:

  • 编写可移植、无侵入且易于维护的代码
  • 灵活管理对象生命周期,可选择是否拥有所有权
  • 实现的性能可与手写代码相媲美甚至更优
  • 从任意表达式中构建抽象:包括成员函数、自由函数、运算符、类型转换等

如果你刚接触 Proxy,不妨查看我们的 GitHub 代码仓库以及之前的公告:宣布推出支持动态多态的 Proxy 3 库分析“Proxy”库的性能

新网站:一站式参考指南

我们推出了一个全新的文档网站,基于 MkDocs 构建,助你找到关于 Proxy 的所有所需信息。新网站优化了导航布局,整合了常见问题解答,并为所有功能和 API 设计了清晰的结构。浏览文档,开启你的使用之旅吧!

立即在 Compiler Explorer 中试用 Proxy

现在你可以直接在浏览器中通过Compiler Explorer来试用 Proxy 了!无需任何安装,即可编写、运行并查看 Proxy 代码。只需在 Compiler Explorer 中点击“库”并搜索“proxy”,或者使用我们示例中的共享链接即可开始体验。这是了解 Proxy 实际应用并与他人分享你的发现的绝佳方式。

 

Proxy 4 有哪些新功能?

技能:可组合的外观功能

我们来看看为你的类型添加格式支持有多简单(在 Compiler Explorer 中运行):

#include <format>
#include <proxy/proxy.h>

struct Formattable : pro::facade_builder
    ::add_skill<pro::skills::format>
    ::build {};

int main() {
  pro::proxy<Formattable> p = pro::make_proxy<Formattable>(123);
  std::cout << std::format("{}\n", *p); // Prints "123"
}

技能是可复用的构建模块,只需一行代码,你就能为你的门面添加强大的功能:

技能易于组合和扩展。你还可以编写内部的、特定领域的技能来捕获各类模式(日志记录、指标挂钩、验证、检测),这样团队就能复用一个经过充分审核的定义,而不必重复制定约定。这能提升一致性和长期可维护性。更多信息请参阅技能文档

便捷的借用与弱引用

Proxy 4 为非拥有式引用和弱引用提供了便捷的别名:proxy_view 和 weak_proxy。这些功能基于核心的 proxy 概念构建,让你能更轻松地在代码中表达借用和弱所有权模式。例如,你可以使用 proxy_view 安全地借用对象而不获取其所有权,或使用 weak_proxy 创建一个可在需要时锁定的弱引用。有关详细信息,请参阅 proxy_view 文档和 weak_proxy 文档

共享所有权变得简单

借助全新的 make_proxy_shared 和 allocate_proxy_shared 应用程序编程接口(API),你可以高效地创建共享代理和弱代理,无需承担 std::shared_ptr 带来的额外开销。这些应用程序编程接口(API)采用紧凑的内部指针类型,确保了高性能与低内存占用。如需了解更多信息,可查看 make_proxy_shared 文档和 allocate_proxy_shared 文档

更智能的分发与转换

轻松实现递归外观模式

Proxy 4 引入了 facade_aware_overload_t,它允许你定义递归约定,这些约定可引用外观本身,且无需强制提前实例化。这对于返回相同外观的新 proxy对象的运算符链式模式(如算术运算或字符串拼接)特别有用。示例:

#include <format>
#include <iostream>
#include <proxy/proxy.h>

template <class F>
using BinaryOverload =
    pro::proxy<F>(const pro::proxy_indirect_accessor<F>& rhs) const;

template <class T, pro::facade F>
pro::proxy<F> operator+(const T& value,
                        const pro::proxy_indirect_accessor<F>& rhs)
  requires(!std::is_same_v<T, pro::proxy_indirect_accessor<F>>)
{
  return pro::make_proxy<F, T>(value + proxy_cast<const T&>(rhs));
}

struct Addable
    : pro::facade_builder              // Compose capabilities
      ::add_skill<pro::skills::rtti>   // RTTI support
      ::add_skill<pro::skills::format> // Formatting support
      ::add_convention<pro::operator_dispatch<"+">,
                       pro::facade_aware_overload_t<BinaryOverload>> // Recursive operator
      ::build {};

int main() {
  pro::proxy<Addable> p1 = pro::make_proxy<Addable>(1);
  pro::proxy<Addable> p2 = pro::make_proxy<Addable>(2);
  pro::proxy<Addable> p3 = *p1 + *p2; // Uses facade-aware overload
  std::cout << std::format("{}\n", *p3); // Prints "3"
}

请查看facade_aware_overload_t文档了解详细信息。

人人可用的质量提升

  • 按位可平凡重定位:代理现在支持可通过 memcpy 移动的类型,默认情况下可实现更快的移动和赋值。这意味着你能获得更好的性能,还能减少样板代码。更多详情请参阅 is_bitwise_trivially_relocatable 文档
  • C++20 模块支持:多亏了 @SidneyCogdill,Proxy 现在附带了 .ixx 文件,可实现极快的构建速度和更好的 IDE 支持。
  • 诊断功能:错误提示现在更加清晰且更具指导性,可帮助你快速理解并修复代码中的问题。
  • 调试体验:Proxy 4 生成的调试符号更优质,这让你能更轻松地在调试器中检查代理,并了解底层的运行机制。
  • 可访问性创作:现在在外观中公开反射和调度功能变得更简单了,所需的样板代码更少,灵活性也更高。
  • 代码生成:代理4优化了间接调度的调用路径,减少了间接调用周围的指令数量。
  • 编译器支持:NVIDIA HPC 已新增至我们支持的工具链中。Proxy 4 可在最新版 GCC、Clang、MSVC 以及 NVIDIA HPC 编译器上通过测试。我们承诺后续将持续让 Proxy 适配这些编译器,包括独立环境。最低版本要求和编译标志请参阅 README 文件。

主版本兼容性

升级小型组件通常很简单,但迁移单体仓库或多模块产品可能颇具挑战性。请遵循以下指南:

  1. 次要版本或补丁升级(例如 3.3.0 → 3.4.0)所有 3.x.y 版本均保留 API/ABI 兼容性,因此程序的不同部分可安全依赖不同的 3.x.y 版本。无需执行特殊操作。
  2. 大版本升级(例如 3.4.0 → 4.0.0)
    • 如果你的当前版本早于 3.4.0,请先迁移至 3.4.0 版本。
    • 从 3.4.0 版本开始,每个主版本都会放入带版本号的内联命名空间(pro::v3pro::v4 等)。当一个翻译单元涉及多个主版本时,需显式限定命名空间:
      pro::v3::foo(); // Proxy 3 API
      pro::v4::foo(); // Proxy 4 API

      最新版本将其命名空间重新导出为内联(默认)命名空间,因此迁移完成后,非限定调用(pro::foo())会解析到最新版本。

    • 这些宏还带有专业限定的别名,例如 PRO4_DEF_MEM_DISPATCH。当同一翻译单元中包含来自多个专业的头文件时,请使用这些形式。
    • 逐步升级子系统,可按模块或按DLL逐个进行。当所有目标仅依赖新的主版本时,移除旧的包含路径,并从构建环境中删除之前的版本。

这些规则让新旧代码能够在过渡期间共存,同时避免违反单定义规则(ODR)。

其他显著变更

摘要

Proxy 4 建立在 Proxy 3 中推出并经过验证的成熟基础之上,它在不重塑模型的前提下进行了针对性的优化。

核心功能(在 Proxy 3 中确立,且在日常使用中仍处于核心地位):

  • 基于表达式的多态性:只需定义一次外观模式,即可让几乎所有表达式(成员调用、自由调用、运算符、显式/隐式转换)都具备多态性。
  • 灵活创建:make_proxy(尽可能内联)、allocate_proxy(自定义分配器)、原始指针绑定、唯一所有权,以及通过 add_convention / add_reflection / add_facade 实现抽象的组合。
  • 单一proxy类型具备全生命周期通用性:同一外观可透明地支持非拥有、唯一、内联或外部管理的对象。
  • 支持重载解析与反射,可实现简洁通用的调用点。

针对 Proxy 4 的优化:

  • 在现有核心基础上构建的用于借用/弱观察的符合人体工程学的别名(proxy_viewweak_proxy)。
  • 基于技能的组合(格式化、RTTI、视图/弱转换、精简布局、{fmt} 集成),以替代重复的约定样板代码。
  • 新的共享/弱创建辅助函数(make_proxy_sharedallocate_proxy_shared)是对使用频率更高的 make_proxy/allocate_proxy 路径的补充(而非替代)。
  • 概念(proxiable_targetinplace_proxiable_target)明确了类型可与 make_proxy 还是 make_proxy_inplace 配合使用的时机,从而提供更早、更精准的诊断信息,而非模板相关的杂乱提示。
  • facade_aware_overload_t 支持递归的外观/运算符定义(例如返回相同外观的算术运算),且无需强制提前实例化。
  • weak_dispatch 用于在某些包含的类型缺少约定时实现优雅降级。
  • 改进的诊断功能、重定位优化(is_bitwise_trivially_relocatable)、模块支持以及更精简的代码生成。

欢迎提出问题和反馈!如果您发现内容不清晰、存在漏洞或文档有缺失,欢迎提交问题或发起拉取请求。

文章翻译于 | Mingxin Wang Senior Software Engineer

...全文
91 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

6,675

社区成员

发帖
与我相关
我的任务
社区描述
微软技术社区为中国的开发者们提供一个技术干货传播平台,传递微软全球的技术和产品最新动态,分享各大技术方向的学习资源,同时也涵盖针对不同行业和场景的实践案例,希望可以全方位地帮助你获取更多知识和技能。
windowsmicrosoft 企业社区
社区管理员
  • 微软技术分享
  • 郑子铭
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

微软技术社区为中国的开发者们提供一个技术干货传播平台,传递微软全球的技术和产品最新动态,分享各大技术方向的学习资源,同时也涵盖针对不同行业和场景的实践案例,希望可以全方位地帮助你获取更多知识和技能。

予力众生,成就不凡!微软致力于用技术改变世界,助力企业实现数字化转型。

试试用AI创作助手写篇文章吧