{"id":102527,"date":"2019-05-29T07:00:00","date_gmt":"2019-05-29T14:00:00","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/oldnewthing\/?p=102527"},"modified":"2019-05-30T06:15:36","modified_gmt":"2019-05-30T13:15:36","slug":"20190529-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20190529-00\/?p=102527","title":{"rendered":"Why does my C++\/WinRT project get errors of the form &#8220;unresolved external symbol &#8230; consume_Something&#8221;?"},"content":{"rendered":"<p>You set up a new C++\/WinRT project and build it, and everything looks great.<\/p>\n<pre>#include &lt;winrt\/Windows.Gaming.Input.h&gt;\r\n\r\nvoid CheckGamepads()\r\n{\r\n    auto gamepads =\r\n        winrt::Windows::Gaming::Input::Gamepad::Gamepads();\r\n    for (auto&amp;&amp; gamepad : gamepads)\r\n    {\r\n        check(gamepad);\r\n    }\r\n}\r\n<\/pre>\n<p>The code builds just fine except that you get a linker error that makes no sense. (Let&#8217;s face it, most linker errors make no sense until you put on your linker-colored glasses.)<\/p>\n<pre style=\"white-space: pre-wrap;\">error LNK2019: unresolved external symbol <!--\r\n-->\"public: struct winrt::<wbr \/>Windows::<wbr \/>Foundation::<wbr \/>Collections::<wbr \/>IIterator&lt;struct <!--\r\n-->winrt::<wbr \/>Windows::<wbr \/>Gaming::<wbr \/>Input::<wbr \/>Gamepad&gt; <!--\r\n-->__thiscall winrt::<wbr \/>impl::<wbr \/>consume_<wbr \/>Windows_<wbr \/>Foundation_<wbr \/>Collections_<wbr \/>IIterable&lt;struct <!--\r\n-->winrt::<wbr \/>Windows::<wbr \/>Foundation::<wbr \/>Collections::<wbr \/>IIterable&lt;struct <!--\r\n-->winrt::<wbr \/>Windows::<wbr \/>Gaming::<wbr \/>Input::<wbr \/>Gamepad&gt;,struct <!--\r\n-->winrt::<wbr \/>Windows::<wbr \/>Gaming::<wbr \/>Input::<wbr \/>Gamepad&gt;::<wbr \/>First(void)const <!--\r\n-->\" (?First@<wbr \/>?$consume_<wbr \/>Windows_<wbr \/>Foundation_<wbr \/>Collections_<wbr \/>IIterable@<wbr \/>U?$IIterable@<wbr \/>W4Gamepad@<wbr \/>Gaming@<wbr \/>Input@<wbr \/>Windows@<wbr \/>winrt@@@<wbr \/>Collections@<wbr \/>Foundation@<wbr \/>Windows@<wbr \/>winrt@@<wbr \/>W4Gamepad@<wbr \/>Gaming@<wbr \/>Input@<wbr \/>45@@<wbr \/>impl@<wbr \/>winrt@@<wbr \/>QBE?<wbr \/>AU?<wbr \/>$IIterator@<wbr \/>W4Gamepad@<wbr \/>Gaming@<wbr \/>Input@<wbr \/>Windows@<wbr \/>winrt@@@<wbr \/>Collections@<wbr \/>Foundation@<wbr \/>Windows@<wbr \/>3@<wbr \/>XZ) <!--\r\n-->referenced in function \"struct winrt::<wbr \/>Windows::<wbr \/>Foundation::<wbr \/>Collections::<wbr \/>IIterator&lt;struct <!--\r\n-->winrt::<wbr \/>Windows::<wbr \/>Gaming::<wbr \/>Input::<wbr \/>Gamepad&gt; <!--\r\n-->__stdcall winrt::<wbr \/>impl::<wbr \/>begin&lt;struct <!--\r\n-->winrt::<wbr \/>Windows::<wbr \/>Foundation::<wbr \/>Collections::<wbr \/>IIterable&lt;struct <!--\r\n-->winrt::<wbr \/>Windows::<wbr \/>Gaming::<wbr \/>Input::<wbr \/>Gamepad&gt;,0&gt;(struct winrt::<wbr \/>Windows::<wbr \/>Foundation::<wbr \/>Collections::<wbr \/>IIterable&lt;struct <!--\r\n-->winrt::<wbr \/>Windows::<wbr \/>Gaming::<wbr \/>Input::<wbr \/>Gamepad&gt; const &amp;)\" (??$begin@<wbr \/>U?$IIterable@<wbr \/>W4Gamepad@<wbr \/>Gaming@<wbr \/>Input@<wbr \/>Windows@<wbr \/>winrt@@@<wbr \/>Collections@<wbr \/>Foundation@<wbr \/>Windows@<wbr \/>winrt@@<wbr \/>$0A@@<wbr \/>impl@<wbr \/>winrt@@<wbr \/>YG?AU?$<wbr \/>IIterator@<wbr \/>W4Gamepad@<wbr \/>Gaming@<wbr \/>Input@<wbr \/>Windows@<wbr \/>winrt@@@<wbr \/>Collections@<wbr \/>Foundation@<wbr \/>Windows@<wbr \/>1@<wbr \/>ABU?$<wbr \/>IIterable@<wbr \/>W4Gamepad@<wbr \/>Gaming@<wbr \/>Input@<wbr \/>Windows@<wbr \/>winrt@@@<wbr \/>3451@@Z)\r\n<\/pre>\n<p>What the heck is going on here?<\/p>\n<p>Take away all the decorations and it boils down to this:<\/p>\n<pre style=\"white-space: pre-wrap;\">unresolved external symbol \"winrt::<wbr \/>impl::<wbr \/>consume_<wbr \/>...<wbr \/>IIterable&lt;...&gt;::<wbr \/>First()\" <!--\r\n-->referenced in function \"begin(winrt::<wbr \/>IIterable&lt;...&gt; const&amp;).\"\r\n<\/pre>\n<p>The linker couldn&#8217;t find a definition for the <code>First<\/code> method.<\/p>\n<p>The answer from the linker&#8217;s point of view is obvious: You called this <code>consume_BlahBlah<\/code> method but never defined it.<\/p>\n<p>Yeah, so tell me something I don&#8217;t know.<\/p>\n<p>Each C++\/WinRT header file contains the information needed to call methods on the classes in that namespace. In our case, we included <code>Windows.Gaming.Input.h<\/code>, which tells us how to call methods on <code>winrt::<\/code><code>Windows::<\/code><code>Gaming::<\/code><code>Input::Gamepad<\/code> objects. That made it possible to call <code>Gamepad::<\/code><code>Gamepads()<\/code>. The resulting <code>gamepads<\/code> variable is a <code>winrt::<\/code><code>Windows::<\/code><code>Foundation::<\/code><code>Collections::<\/code><code>IVectorView&lt;Gamepad&gt;<\/code>. We then use a ranged <code>for<\/code> statement to enumerate them, and that means that we&#8217;re calling methods on the <code>gamepads<\/code> object, which means that we&#8217;re calling methods on a <code>winrt::<\/code><code>Windows::<\/code><code>Foundation::<\/code><code>Collections::<\/code><code>IVectorView<\/code> object.<\/p>\n<p>Ah, but we never told the compiler how to call the methods of <code>IVectorView<\/code>. The <code>Windows.Gaming.Input.h<\/code> header file included only the information to allow the methods of <code>Gamepad<\/code> to be called. &#8220;Okay, I got you all set up for <code>Gamepad<\/code>.&#8221; Any types required from other interfaces were left as forward declarations. &#8220;If you need them, you can get the definitions yourself.&#8221;\u00b9<\/p>\n<p>We used those forward declarations without ever defining them, hence the linker error.<\/p>\n<p>The solution is to include the required header file for the namespace.<\/p>\n<pre>#include &lt;winrt\/Windows.Foundation.Collections.h&gt;\r\n<\/pre>\n<p>This is one of those rookie mistakes that make you scratch your head the first time you encounter it. The need to include the header file is mentioned <a href=\"https:\/\/docs.microsoft.com\/en-us\/windows\/uwp\/cpp-and-winrt-apis\/consume-apis\"> in a big green box in the documentation<\/a>, but that&#8217;s not much consolation after you lost a few hours trying to figure it out.<\/p>\n<p>There&#8217;s some good news and bad news about this error message.<\/p>\n<p>The good news is that this error message is going away. The bad news is that it&#8217;s being replaced with a different error message. (But hopefully the new one is easier to understand.) More details <a href=\"http:\/\/devblogs.microsoft.com\/oldnewthing\/20190530-00\/?p=102529\">next time<\/a>.<\/p>\n<p>\u00b9 The idea is that you pay only for the namespaces you use. If every header file included its transitive closure of dependencies, (1)\u00a0you would create circular dependencies, and (2)\u00a0including a single header file would end up including all the other header files when you chased through all the dependencies.<\/p>\n<p>The idea of &#8220;pay for play&#8221; is not unique to C++\/WinRT. The C++ standard library follows the same principle. If you want <code>std::string<\/code>, <a href=\"https:\/\/stackoverflow.com\/a\/22724103\/902497\"> you need to <code>#include &lt;string&gt;<\/code><\/a>. If you include a header file that has a method that takes a string, you will end up with only enough information to call that method. It doesn&#8217;t mean that you get all of <code>&lt;string&gt;<\/code> automatically.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Declared but not defined, but what exactly wasn&#8217;t defined?<\/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-102527","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Declared but not defined, but what exactly wasn&#8217;t defined?<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/102527","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=102527"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/102527\/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=102527"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=102527"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=102527"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}