{"id":31879,"date":"2023-02-28T16:00:15","date_gmt":"2023-02-28T16:00:15","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/cppblog\/?p=31879"},"modified":"2023-02-28T10:35:55","modified_gmt":"2023-02-28T10:35:55","slug":"an-alternative-to-__if_exists-in-atl","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cppblog\/an-alternative-to-__if_exists-in-atl\/","title":{"rendered":"An alternative to __if_exists in ATL"},"content":{"rendered":"<h3>What are <code>_if_exists<\/code> and <code>__if_not_exists<\/code><\/h3>\n<p>The<code> __if_exists<\/code> and <code>__if_not_exists<\/code> keywords in the Active Template Library (ATL) allow a user to test at compile time whether an identifier exists.\u00a0 If the identifier exists, the associated statement block is executed.\u00a0<code> __if_exists<\/code> and <code>__if_not_exists<\/code> can be applied to the names of variables, functions, typedefs, as well as other identifiers.\u00a0 You can read more about the specifics of their use and potential pitfalls on <a href=\"https:\/\/docs.microsoft.com\/en-us\/cpp\/cpp\/if-exists-statement?view=msvc-170\">MSDN<\/a>, and in Raymond Chen\u2019s <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20190828-00\/?p=102812\">blogpost<\/a> about the keywords.<\/p>\n<h3>Why you shouldn\u2019t use <code>_if_exists<\/code> or <code>__if_not_exists<\/code><\/h3>\n<p>Although these keywords seem like they\u2019d be useful, they\u2019ve been problematic for years.\u00a0 Also, <code>_if_exists<\/code> and <code>__if_not_exists<\/code> are also incompatible with the recommended compiler <code>\/permissive-<\/code> switch, which specifies standards-conforming compiler behavior, thus they also can\u2019t be used with the new C++20 modules feature.<\/p>\n<h3>Alternatives to <code>__if_exists<\/code> and <code>__if_not_exists<\/code><\/h3>\n<p>Starting with Visual Studio 2022 17.2 Preview 3, because MSVC with <code>\/permissive-<\/code> (required by modules!) doesn&#8217;t support <code>__if_exists<\/code>, ATL has a new macro\u2014 <code>_ATL_MODULES<\/code>\u2014which will replace code that looks like:<\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">__if_exists(m_nAccessors)<\/code><\/pre>\n<p>with code that looks like:<\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">if constexpr(_Has_m_nAccessors&lt;_Self&gt;::value)<\/code><\/pre>\n<p>By default, you can still use <code>__if_exists<\/code> and <code>__if_not_exists<\/code>, and you can use the old ATL code, but if you wish to use the modern <code>\/permissive-<\/code> compiler mode, you&#8217;ll need to switch. Notice that is only supported from c++ 17 and forward.<\/p>\n<h3>Changes in ATL Macros<\/h3>\n<p>Some ATL Macros were affected by the removal of <code>__if_exists<\/code>. You need to be aware of the following changes:<\/p>\n<ul>\n<li>There are now two versions of <code>BEGIN_PROPERTY_MAP<\/code> and <code>BEGIN_PROP_MAP<\/code>: <code>*_WITHOUT_ATL_PROP_NOTIFY_EVENT_CLASS_TYPEDEF<\/code> should be used in classes where there is <em>no<\/em> <code>_ATL_PROP_NOTIFY_EVENT_CLASS<\/code> typedef; <code>*_WITH_ATL_PROP_NOTIFY_EVENT_CLASS<\/code> versions should be used in classes where there <em>is <\/em>an <code>_ATL_PROP_NOTIFY_EVENT_CLASS<\/code> typedef.<\/li>\n<li><code>DECLARE_REGISTRY_RESOURCE<\/code>, <code>DECLARE_REGISTRY_RESOURCE_ID<\/code> \u2013 These macros have new versions.\n<ul>\n<li><code>WITH_MODULE<\/code> should be used where there is a global variable named <code>_Module<\/code> that is of a subtype of <code>CComModule<\/code><\/li>\n<li><code>WITHOUT_MODULE<\/code> version should be used when there is no such global variable available.<\/li>\n<li>V2 versions: In order for the new macros to emulate the original <code>__if_exists<\/code> behavior we need to know the name of the containing class. The previous versions of the macros do so using a non-Standard MSVC-specific extension.\u00a0 The new versions require the user to pass the name of the containing class to the macro.\u00a0 Whenever possible users should use the V2 versions.<\/li>\n<\/ul>\n<\/li>\n<li><code>BEGIN_CONNECTION_POINT_MAP<\/code>, <code>BEGIN_ATTRCONNECTION_POINT_MAP<\/code> \u2013 These macros define the typedef <code>_atl_conn_classtype<\/code> if it wasn\u2019t already defined. Because we cannot detect if it already exists, there are now two versions of these macros:\n<ul>\n<li><code>*_WITHOUT_ATL_CONN_CLASSTYPE_TYPEDEF<\/code> should be used if there is <em>no<\/em> <code>_atl_conn_classtype<\/code> typedef<\/li>\n<li><code>*_WITH_ATL_CONN_CLASSTYPE_TYPEDEF<\/code> should be used \u00adin classes where there <em>is <\/em>an <code>_atl_conn_classtype<\/code> typedef already existing<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3>Why you should consume the ATL with the <code>_ATL_MODULES<\/code> flag<\/h3>\n<p>One of the most important consequences of these changes is that ATL can now be used with header units!\u00a0 Read more about the benefits of Modules, including improved throughput, here (<a href=\"https:\/\/learn.microsoft.com\/cpp\/build\/walkthrough-header-units\">https:\/\/learn.microsoft.com\/cpp\/build\/walkthrough-header-units<\/a>)<\/p>\n<p>Special thanks to Miya Natsuhara, who made all of these changes on the ATL codebase.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>What are _if_exists and __if_not_exists The __if_exists and __if_not_exists keywords in the Active Template Library (ATL) allow a user to test at compile time whether an identifier exists.\u00a0 If the identifier exists, the associated statement block is executed.\u00a0 __if_exists and __if_not_exists can be applied to the names of variables, functions, typedefs, as well as other [&hellip;]<\/p>\n","protected":false},"author":43133,"featured_media":35994,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-31879","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cplusplus"],"acf":[],"blog_post_summary":"<p>What are _if_exists and __if_not_exists The __if_exists and __if_not_exists keywords in the Active Template Library (ATL) allow a user to test at compile time whether an identifier exists.\u00a0 If the identifier exists, the associated statement block is executed.\u00a0 __if_exists and __if_not_exists can be applied to the names of variables, functions, typedefs, as well as other [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/31879","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/users\/43133"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/comments?post=31879"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/31879\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media\/35994"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media?parent=31879"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/categories?post=31879"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/tags?post=31879"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}