{"id":105733,"date":"2021-09-27T07:00:00","date_gmt":"2021-09-27T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=105733"},"modified":"2021-09-27T06:38:06","modified_gmt":"2021-09-27T13:38:06","slug":"20210927-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210927-00\/?p=105733","title":{"rendered":"Why am I getting an unresolved external from C++\/WinRT if it is a header-only C++ library?"},"content":{"rendered":"<p>A customer was getting unresolved external errors from their C++\/WinRT code. How is that possible? C++\/WinRT is a header-only library; there is no static library that needs to be linked in. I mean, the way to resolve an unresolved external from a header is to link in the associated static or dynamic library, but for header-only libraries, there is no associated <i>anything<\/i> to link in. So how can something be unresolved?<\/p>\n<p>C++\/WinRT is not just one header, but a series of headers. To reduce compile times, the C++\/WinRT headers for a particular component are split into multiple layers of headers. The lowest layer provides forward declarations for types, but almost no definitions. As you go higher up the layers, you get a little more: Maybe a class gets a definition, but the methods don&#8217;t get implemented until a still higher layer.<\/p>\n<p>When you include a C++\/WinRT header file, it includes declarations, definitions, and implementations for everything for which that header file is responsible, as well as its parent namespaces, but no more.<\/p>\n<p>Consider:<\/p>\n<pre>namespace Contoso.Widgets\r\n{\r\n    runtimeclass Widget\r\n    {\r\n        Widget();\r\n        Contoso.Gadgets.Gadget GetGadget();\r\n        void Reset();\r\n    }\r\n}\r\n<\/pre>\n<p>If you include <code>winrt\/Contoso.Widgets.h<\/code>, you get everything you need to create a <code>Widget<\/code> and call its methods. However, you <i>don&#8217;t<\/i> get everything you need to operate on <code>Gadget<\/code> objects. You do have enough to call the <code>GetGadget()<\/code> method, but you can&#8217;t do anything with the gadget until you include <code>winrt\/Contoso.Gadgets.h<\/code>.<\/p>\n<p>Normally, when you make this mistake, you get a compile-time error thanks to <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20190530-00\/?p=102529\"> a trick<\/a>: Declare the methods as <code>auto<\/code>. An <code>auto<\/code> method must be defined before it can be called, and that&#8217;s the language feature that the trick relies on.\u00b9<\/p>\n<p>However, this trick doesn&#8217;t work for constructors and destructors, since they don&#8217;t have return values that can be <code>auto<\/code>-ized. If you use a constructor for a type without having included the corresponding namespace header file, the code will compile, and you&#8217;ll get a linker error later.\u00b2<\/p>\n<p>Sorry.<\/p>\n<p>\u00b9 The methods are, however, defined with a return value in the normal way if <code>__INTELLISENSE__<\/code> is defined, so that you get more useful feedback from IntelliSense.<\/p>\n<p>\u00b2 Well, if you&#8217;re lucky and some other translation unit included the namespace header file and used the constructor, then you will get a definition, but that&#8217;s only because you were relying on the kindness of strangers.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Maybe you didn&#8217;t get all of the headers.<\/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-105733","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Maybe you didn&#8217;t get all of the headers.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105733","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=105733"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105733\/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=105733"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=105733"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=105733"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}