{"id":106012,"date":"2021-12-08T07:00:00","date_gmt":"2021-12-08T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106012"},"modified":"2021-12-08T06:57:23","modified_gmt":"2021-12-08T14:57:23","slug":"20211208-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20211208-00\/?p=106012","title":{"rendered":"Using CRTP to your advantage: Simplifying overloaded Windows Runtime method projections in C++\/WinRT"},"content":{"rendered":"<p>C++\/WinRT uses the so-called the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Curiously_recurring_template_pattern\"> curiously recurring template pattern<\/a>, commonly known as CRTP. One of the nice features of CRTP is that the derived class method signature does not have to be a perfect match for the signature expected by the base class. All that matters is that the base class can call it <i>as if<\/i> it had the expected signature.\u00b9<\/p>\n<p>It is common in the Windows Runtime to have overloads of the same method, where the extra parameters, if omitted, take on fixed default values:<\/p>\n<pre>namespace Contoso\r\n{\r\n    enum WidgetToggleOptions\r\n    {\r\n        Default,\r\n        UseBothHands,\r\n    };\r\n\r\n    runtimeclass Widget\r\n    {\r\n        bool Toggle(); \/\/ defaults to WidgetToggleOptions.Default\r\n        bool Toggle(WidgetToggleOptions options);\r\n    }\r\n}\r\n<\/pre>\n<p>The na\u00efve implementation would go like this:<\/p>\n<pre>namespace winrt::Contoso::implementation\r\n{\r\n    struct Widget : WidgetT&lt;Widget&gt;\r\n    {\r\n        bool Toggle();\r\n        bool Toggle(WidgetToggleOptions options);\r\n    };\r\n\r\n    bool Widget::Toggle()\r\n    {\r\n        return Toggle(WidgetToggleOptions::Default);\r\n    }\r\n\r\n    bool Widget::Toggle(WidgetToggleOptions options)\r\n    {\r\n        ... implementation ...\r\n    }\r\n}\r\n<\/pre>\n<p>For each overload, we implement a corresponding function in the CRTP derived class for the base class to forward to.<\/p>\n<p>But you&#8217;re working too hard.<\/p>\n<p>The base class is going to call <code>Widget::Toggle()<\/code>, but that doesn&#8217;t mean that the signature must be exactly <code>Widget::Toggle()<\/code>. You have been taking advantage of this already: A method whose Windows Runtime signature is <code>void Method(String name)<\/code> can be implemented with any of these signatures:<\/p>\n<pre>void Method(winrt::hstring name);\r\nvoid Method(winrt::hstring const&amp; name);\r\nwinrt::fire_and_forget Method(winrt::hstring name);\r\n<\/pre>\n<p>So let&#8217;s take advantage of it some more: We can write one implementation that covers both projected methods by using default parameters.<\/p>\n<pre>namespace winrt::Contoso::implementation\r\n{\r\n    struct Widget : WidgetT&lt;Widget&gt;\r\n    {\r\n        bool Toggle(WidgetToggleOptions options = WidgetToggleOptions::Default);\r\n    };\r\n\r\n    bool Widget::Toggle(WidgetToggleOptions options)\r\n    {\r\n        ... implementation ...\r\n    }\r\n}\r\n<\/pre>\n<p>When the CRTP base class tries to call <code>Widget::Toggle()<\/code>, it will call the <code>Toggle(WidgetToggleOptions options)<\/code> method, using the default parameter of <code>WidgetToggleOptions::Default<\/code> to fill in the missing explicit parameter.<\/p>\n<p>I think this approach is easier to read, especially when there are multiple overloads with longer and longer parameter lists, since it lets you see the behavior of the short-parameter-list versions at a glance, and avoids any risk of the various overloads falling out of sync.<\/p>\n<p>\u00b9 This is similar to the rule in the C++ language specification (<b>[namespace.std]<\/b>) which permits standard library functions to have additional default function parameters or default template parameters, as long as they are callable via the standard-prescribed signatures. (There is an exception for so-called <i>addressable functions<\/i>, which must have exactly the standard-specified signature.) This rule exists so that the implementation can use these default parameters to control which functions participate in overloading, or which templates can be instantiated (via SFINAE). The way the rule is expressed in the standard is &#8220;A program may not take the address of a standard library function.&#8221;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>As long as the wrapper can call it, you can implement it any way you like.<\/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-106012","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>As long as the wrapper can call it, you can implement it any way you like.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106012","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=106012"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106012\/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=106012"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106012"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106012"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}