__if_exists 和 __if_not_exists 是什么?
__if_exists 和 __if_not_exists 是微软 ATL (Active Template Library,活动模板库) 中的关键字,可以用来在编译期间测试一个标识符是否存在。如果该标识符存在,则其关联的语句将会被执行。
__if_exists 和 __if_not_exists 可以用在变量,函数,typedef 以及其他标识符上。
关于这个关键字的使用和潜在的误用,可以参考 Raymond Chen 的相关博客。
为什么你不应该使用 __if_exists 和 __if_not_exists
尽管这些关键字看起来很有用,但它们多年来一直存在问题。 此外,__if_exists 和 __if_not_exists 也与推荐的编译器 /permissive- switch 不兼容,后者指定了符合标准的编译器行为,因此它们也不能与新的 C++20 模块功能一起使用。
替代方案
从 Visual Studio 2022 17.2 预览版 3 开始,由于带有 /permissive- (模块需要!)的 MSVC 不支持__if_exists,因此 ATL 有一个新的宏 — _ATL_MODULES — 它将替换如下所示的代码:
__if_exists(m_nAccessors)
替代为:
if constexpr(_Has_m_nAccessors<_Self>::value)
默认情况下,你仍然可以使用 __if_exists 和 __if_not_exists,并且可以使用旧的 ATL 代码,但如果要使用现代 /permissive- 编译器模式,则需要切换。请注意,仅 c++ 17 及更高版本支持此功能。
ATL中宏的更改
某些 ATL 宏受到删除__if_exists的影响。请注意以下更改:
> 现在有两个版本的 BEGIN_PROPERTY_MAP 和 BEGIN_PROP_MAP:*
_WITHOUT_ATL_PROP_NOTIFY_EVENT_CLASS_TYPEDEF 应该在没有 typedef _ATL_PROP_NOTIFY_EVENT_CLASS的类中使用;*_WITH_ATL_PROP_NOTIFY_EVENT_CLASS 版本应该存在_ATL_PROP_NOTIFY_EVENT_CLASS typedef 的类中使用。
> DECLARE_REGISTRY_RESOURCE,
DECLARE_REGISTRY_RESOURCE_ID – 这些宏具有新版本。
> WITH_MODULE 应该在存在名为 _Module 的全局变量(属于 CComModule 的子类型)时使用
> 当没有此类全局变量可用时,应使用WITHOUT_MODULE版本。
> V2 版本:为了使新宏模拟原始__if_exists行为,我们需要知道包含类的名称。以前版本的宏使用非标准 MSVC 特定的扩展执行此操作。 新版本要求用户将包含类的名称传递给宏。 用户应尽可能使用 V2 版本。
>
BEGIN_CONNECTION_POINT_MAP,BEGIN_ATTRCONNECTION_POINT_MAP – 这些宏定义 typedef _atl_conn_classtype(如果尚未定义)。由于我们无法检测它是否已存在,因此现在这些宏有两个版本:
> *
_WITHOUT_ATL_CONN_CLASSTYPE_TYPEDEF 如果没有_atl_conn_classtype typedef ,则应使用
> *
_WITH_ATL_CONN_CLASSTYPE_TYPEDEF 应该在已经存在 _atl_conn_classtype typedef 的类中使用
为什么应该使用带有 _ATL_MODULES 标志的 ATL
最重要的原因是:ATL 现在可以与头文件单元一起使用了。
总结
这些巨型宏看起来挺复杂,但我们应该追随趋势,不能和趋势作对。
既然老大哥说让我们改,我们最好还是照办。
另外一个方法是:完全不使用 ATL,自己造轮子。
最后
Microsoft Visual C++团队的博客是我非常喜欢的博客之一,里面有很多关于Visual C++的知识和最新开发进展。大浪淘沙,如果你对Visual C++这门古老的技术还是那么感兴趣,则可以经常去他们那(或者我这)逛逛。
本文来自:《An alternative to __if_exists in ATL》