{"id":107944,"date":"2023-03-16T07:00:00","date_gmt":"2023-03-16T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=107944"},"modified":"2023-03-16T10:00:31","modified_gmt":"2023-03-16T17:00:31","slug":"20230316-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230316-00\/?p=107944","title":{"rendered":"Mind your C++\/WinRT namespaces"},"content":{"rendered":"<p>When you implement a Windows Runtime class in C++\/WinRT, each class name appears in three different namespace, so you need to mind your namespaces.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<th>Projection<\/th>\n<td><code>winrt::<wbr \/>Namespace::<wbr \/>ClassName<\/code><\/td>\n<\/tr>\n<tr>\n<th>Factory<\/th>\n<td><code>winrt::<wbr \/>Namespace::<wbr \/>factory_<wbr \/>implementation::<wbr \/>ClassName<\/code><\/td>\n<\/tr>\n<tr>\n<th>Implementation<\/th>\n<td><code>winrt::<wbr \/>Namespace::<wbr \/>implementation::<wbr \/>ClassName<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>If you write an unqualified <code>ClassName<\/code>, the compiler searches for the name in the current namespace, then the parent namespace, then the grandparent namespace, and so on until it reaches the global namespace.<\/p>\n<p>Now, when you say <code>ClassName<\/code>, there&#8217;s a decent chance that you intend to refer to the name in the projection namespace, particularly if you copy\/pasta&#8217;d some code from a tutorial or from another project. What you didn&#8217;t realize is that the code you copied was intended to be compiled outside the implementation namespaces. But if you happen to be in one of the implementation namespaces, you will pick up the name in that other namespace by mistake.<\/p>\n<pre>namespace winrt::MyNamespace::implementation\r\n{\r\n    struct ClassName : ClassNameT&lt;ClassName&gt;\r\n    {\r\n        ClassName CreateChild()\r\n        { return make&lt;ClassName&gt;(...); }\r\n\r\n        Windows::Foundation::IAsyncOperation&lt;ClassName&gt;\r\n            CreateChildAsync()\r\n        {\r\n            \/* do stuff *\/\r\n            co_return make&lt;ClassName&gt;(...);\r\n        }\r\n    };\r\n}\r\n\r\nnamespace winrt::MyNamespace::factory_implementation\r\n{\r\n    struct ClassName : ClassNameT&lt;ClassName, implementation::ClassName&gt;\r\n    {\r\n        static ClassName Create()\r\n        { return make&lt;ClassName&gt;(); }\r\n    };\r\n}\r\n<\/pre>\n<p>The above code wants the <code>CreateChild()<\/code> method to return a Windows Runtime <code>ClassName<\/code> object, but since the name <code>ClassName<\/code> is being used inside the <code>winrt::<wbr \/>Namespace::<wbr \/>implementation<\/code> namespace, it actually refers to the <code>winrt::<wbr \/>Namespace::<wbr \/>implementation::<wbr \/>ClassName<\/code> implementation type, not the projection type.<\/p>\n<p>Similarly, the <code>Create()<\/code> method on the factory class intends to return a Windows Runtime <code>ClassName<\/code> object, but instead it returns a <code>winrt::<wbr \/>Namespace::<wbr \/>factory_<wbr \/>implementation::<wbr \/>ClassName<\/code> object.<\/p>\n<p>The result of this incorrect name lookup is usually a pair of really confusing error messages.<\/p>\n<p>You get one error message when the compiler realizes that the <code>return make&lt;ClassName&gt;(...)<\/code> is trying to return a projected type, but the declared return type is one of the implementation types, so you are scolded that there is no conversion from the projection type to the implementation type.<\/p>\n<p>You get a second error message when the compiler instantiates the <code>ClassNameT<\/code> template, which uses the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Curiously_recurring_template_pattern\"> Curiously Recurring Template Pattern<\/a> (commonly known as CRTP). The <code>ClassNameT<\/code> template expects the <code>CreateChild()<\/code> and <code>Create()<\/code> methods to return the projected type, but their declared return type is an implementation type, and you get scolded a second time because there is no conversion from the implementation type to the projection type.<\/p>\n<p>The <code>CreateChildAsync()<\/code> method is even worse. In this case, we accidentally said that it returns an <code>IAsyncOperation&lt;<wbr \/>implementation::<wbr \/>ClassName&gt;<\/code>. This mistake is also rewarded with not just two but <i>three<\/i> confusing error messages, which could be reported in any order.<\/p>\n<p>As before, there is a problem from the CRTP code that the declared return type doesn&#8217;t match what the CRTP code expects.<\/p>\n<p>And analogously, you get an error at the <code>co_return<\/code> because the coroutine expects you to <code>co_return<\/code> the implementation type (since that&#8217;s the accidental template type parameter to <code>IAsyncOperation<\/code>), but you <code>co_return<\/code>ed the projection type. This error message is a little confusing because it is typically reported as a problem with the promise&#8217;s <code>return_value<\/code> method, since the argument to <code>co_return<\/code> <a title=\"C++ coroutines: Accepting types via return_void and return_value\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210407-00\/?p=105061\"> gets passed to the promise&#8217;s <code>return_value<\/code> method<\/a>.<\/p>\n<p>The third mysterious error message comes from <code>IAsyncOperation<\/code> because one of the requirements is that the template type parameter (the thing produced by the <code>IAsyncOperation<\/code>) must be a Windows Runtime type, and the Windows Runtime type is your projection type, not the implementation types.<\/p>\n<p>Okay, so we learned that using an unqualified type name from inside the implementation or factory implementation namespace gives you the corresponding implementation type, not the projection type. But what if you want the implementation type?<\/p>\n<p>In theory, you could type the full name <code>winrt::<wbr \/>Namespace::<wbr \/>ClassName<\/code>, but really, all you have to say is <code>Namespace::<wbr \/>ClassName<\/code>. The lookup proceeds through the parent namespaces, and it finds a match when it gets to <code>winrt<\/code>.<\/p>\n<p>This shortcut is particularly handy when you have a deep namespace. Instead of the full name <code>winrt::<wbr \/>Grandparent::<wbr \/>Parent::<wbr \/>Namespace::<wbr \/>ClassName<\/code>, you can write just <code>Namespace::<wbr \/>ClassName<\/code>.<\/p>\n<p><b>Bonus chatter<\/b>: All this confusion stems from the fact that we used the same name in three namespaces. We could have avoided this by using different names for our two implementation classes, so that they don&#8217;t collide with the projected class name, or with each other.<\/p>\n<pre>namespace winrt::MyNamespace::implementation\r\n{\r\n    struct ClassName<span style=\"color: #08f;\">Impl<\/span> : ClassNameT&lt;ClassName<span style=\"color: #08f;\">Impl<\/span>&gt;\r\n    {\r\n        ClassName CreateChild()\r\n        { return make&lt;ClassName<span style=\"color: #08f;\">Impl<\/span>&gt;(...); }\r\n\r\n        Windows::Foundation::IAsyncOperation&lt;ClassName&gt;\r\n            CreateChildAsync()\r\n        {\r\n            \/* do stuff *\/\r\n            co_return make&lt;ClassName<span style=\"color: #08f;\">Impl<\/span>&gt;(...);\r\n        }\r\n    };\r\n}\r\n\r\nnamespace winrt::MyNamespace::factory_implementation\r\n{\r\n    struct ClassName<span style=\"color: #08f;\">Fact<\/span> : ClassNameT&lt;ClassName<span style=\"color: #08f;\">Fact<\/span>, implementation::ClassName<span style=\"color: #08f;\">Impl<\/span>&gt;\r\n    {\r\n        static ClassName Create()\r\n        { return make&lt;ClassName<span style=\"color: #08f;\">Fact<\/span>&gt;(); }\r\n    };\r\n}\r\n<\/pre>\n<p>This way, <code>ClassName<\/code> always refers to the projection class.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>What you say changes meaning depending on where you are.<\/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-107944","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>What you say changes meaning depending on where you are.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107944","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=107944"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107944\/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=107944"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=107944"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=107944"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}