使用 C++ 类型别名来避免条件编译的 ODR 问题,第 1 部分 - 《The Old New Thing》

主要观点:

  • 讨论了 C++中“不良格式但无需诊断(IFNDR)”的概念,常见的意外来源是违反“单一定义规则(ODR)”,通过基于编译时开关定义不同的类或函数。
  • Widget类为例,若不同的.cpp文件根据编译时开关有不同的定义,链接时会违反 ODR。
  • 类型别名不受 ODR 限制,可在不同翻译单元中有不同定义。
  • 通过模板WidgetT实现了不同调试版本和非调试版本的Widget,并通过外部模板声明和别名来选择使用。
  • 模板的实现不在头文件中,需要显式实例化模板以触发代码生成。
  • 当客户端使用widget.h头文件时,可根据调试设置选择不同的Widget版本,但不同版本之间的交互可能导致链接错误,如在类中使用Widget或在全局函数中返回Widget时。

关键信息:

  • Widget类中根据编译时开关有不同的Log方法定义。
  • WidgetT模板有调试和非调试版本,分别有Loggerstd::monostate成员。
  • 需显式实例化WidgetT模板。
  • 客户端使用的Widget别名不同可能导致链接错误,类或全局函数中使用Widget也可能引发 ODR 违规。

重要细节:

  • [msvc::no_unique_address]属性用于告知编译器可将空对象折叠为无,在非调试时消失。
  • 若一个客户端暴露的类使用Widget,不同调试设置的客户端可能对该类中Widget的版本有不同理解,引发 ODR 违规。
  • 提到类似技术可用于处理wchar_t的多种可能定义,并给出相关阅读链接。
阅读 13
0 条评论