{"id":105852,"date":"2021-10-28T07:00:00","date_gmt":"2021-10-28T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=105852"},"modified":"2021-10-28T10:17:10","modified_gmt":"2021-10-28T17:17:10","slug":"20211028-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20211028-00\/?p=105852","title":{"rendered":"Giving a single object multiple COM identities, part 3"},"content":{"rendered":"<p>Last time, we left off our investigation of how to <a title=\"Giving a single object multiple COM identities, part 2\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20211027-00\/?p=105838\"> give a single object multiple COM identities<\/a> without any data overhead, by tricking the compiler into generating the adjustor thunks automatically. We had managed to build the callbacks into base classes, using base classes means that we&#8217;re back to the problem of having multiple implementations of <code>IUnknown<\/code>, which the C++ language does not permit to implement separately. We saw that the standard workaround for this is to move the <code>ICallback<\/code> into a member variable.<\/p>\n<pre>template&lt;auto Callback&gt;\r\nstruct CallbackWrapper\r\n{\r\n    template&lt;typename Outer&gt; static Outer outer_type(void(Outer::*)());\r\n    using Outer = typename decltype(outer_type(Callback))::Outer;\r\n\r\n    struct Wrapper : ICallback\r\n    {\r\n        HRESULT QueryInterface(REFIID riid, void** ppv)\r\n        {\r\n            if (riid == IID_IUnknown || riid == IID_ICallback) {\r\n                *ppv = static_cast&lt;ICallback*&gt;(this);\r\n                AddRef();\r\n                return S_OK;\r\n            }\r\n            *ppv = nullptr;\r\n            return E_NOINTERFACE;\r\n        }\r\n\r\n        ULONG AddRef() { return outer()-&gt;AddRef(); }\r\n        ULONG Release() { return outer()-&gt;Release(); }\r\n\r\n        HRESULT Invoke() noexcept { return (outer()-&gt;*Callback)(); }\r\n\r\n        private:\r\n        Outer* outer() {\r\n            return static_cast&lt;Outer*&gt;(\r\n                reinterpret_cast&lt;CallbackWrapper*&gt;(this));\r\n        }\r\n    } callback;\r\n\r\n    ICallback* GetCallback() { return &amp;callback; }\r\n};\r\n<\/pre>\n<p>This code makes the assumption that the first instance data member of a class with no virtual methods be pointer-interconvertible with the class itself. According to the standard, this assumption is valid only for standard-layout types, and <code>CallbackWrapper<\/code> is not a standard layout type because it has a member <code>callback<\/code> which is not a standard-layout type. On the other hand, in practice the assumption holds. We can add some extra assertions to verify this:<\/p>\n<pre>template&lt;auto Callback&gt;\r\nstruct CallbackWrapper\r\n{\r\n    ...\r\n    \r\n    <span style=\"color: blue;\">CallbackWrapper() {\r\n        assert(reinterpret_cast&lt;void*&gt;(this) == &amp;callback);\r\n    }<\/span>\r\n};\r\n\r\ntemplate&lt;auto Callbacks...&gt;\r\nstruct CallbackWrapper : CallbackWrapper&lt;Callbacks&gt;...\r\n{\r\n    <span style=\"color: blue;\">static_assert(((offsetof(CallbackWrapper&lt;Callbacks&gt;, callback) == 0) &amp;&amp; ...));<\/span>\r\n    template&lt;auto Callback&gt;\r\n    ICallback* GetCallback() {\r\n        return static_cast&lt;CallbackWrapper&lt;Callback&gt;*&gt;(this);\r\n    }\r\n};\r\n<\/pre>\n<p>We add a static assertion that verifies that the member variable <code>callback<\/code> has the same address as the containing class <code>Callback\u00adWrapper<\/code> in all of the base classes. The proliferation of parentheses comes from the language rules for fold expressions:<\/p>\n<pre>    (expr &amp;&amp; ...)\r\n<\/pre>\n<p>The outer parentheses around the fold expression are mandatory. Furthermore, the <code>expr<\/code> must be a <i>cast-expression<\/i>. The equality comparison operator is lower precedence than a cast, so we need to parenthesize it to turn it into a higher-priority <i>primary-expression<\/i>. And the final extra set of parentheses come from the syntax of <code>static_assert<\/code> itself, which requires that its argument be parenthesized.<\/p>\n<p>Now, this compile-time check is not standard-conforming, because the <code>offsetof<\/code> macro supports only standard-layout types (although it works well enough in practice), so we supplement it with a runtime assertion.\u00b9<\/p>\n<p>With all these changes, the resulting code generation is quite efficient:<\/p>\n<pre>CallbackWrapper&lt;&amp;WidgetImpl&lt;Widget&gt;::OnCallback1&gt;::OnCallback1:\r\n    sub     rcx, 8\r\n    jmp     Widget::OnCallback1\r\n<\/pre>\n<p>If you throw in link-time code generation, then the compiler will even notice that <code>Widget::<wbr \/>OnCallback1<\/code> is called from only one place, so it will inline it into the <code>Callback\u00adWrapper<\/code>, resulting in the wrapper ending up with no cost at all. (The adjustment of the <code>this<\/code> pointer can be reduced to zero cost by folding it into the subsequent member offsets.)<\/p>\n<p>Having to create the <code>MethodWrapper<\/code> class is a bit of an annoyance, though. You have to put into that class every function you might want to forward. (Fortunately, it&#8217;s okay to have methods corresponding to functions you never use, since they will never be instantiated, and therefore the compiler will never notice that the forwarded-to function doesn&#8217;t exist.)<\/p>\n<p>We&#8217;ll try to simplify that next time.<\/p>\n<p>\u00b9 The standard does require that a union be pointer-interconvertible with its members, so we could have made the <code>Callback\u00adWrapper<\/code> be a union with the <code>Wrapper<\/code> as its sole member. However, unions cannot be base classes, so that messes up the &#8220;Derive from this thing&#8221; step.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Returning to the scene of the crime.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-105852","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Returning to the scene of the crime.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105852","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=105852"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105852\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=105852"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=105852"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=105852"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}