{"id":111285,"date":"2025-06-19T07:00:00","date_gmt":"2025-06-19T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=111285"},"modified":"2025-06-19T06:27:49","modified_gmt":"2025-06-19T13:27:49","slug":"20250619-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20250619-00\/?p=111285","title":{"rendered":"Learning to read C++ compiler errors: Ambiguous symbol errors after including a header file"},"content":{"rendered":"<p>A colleague added another header file to their project, and everything started blowing up with &#8220;ambiguous symbol&#8221; errors.<\/p>\n<pre>#include \"pch.h\"\r\n#include \"something.h\"\r\n<span style=\"border: solid 1px currentcolor;\">#include \"newheader.h\"<\/span>\r\n#include &lt;shlobj.h&gt;\r\n\r\n...\r\n<\/pre>\n<p>This resulted in a build error in Visual Studio:<\/p>\n<pre style=\"white-space: pre-wrap;\">D:\\Program Files (x86)\\<wbr \/>Windows Kits\\<wbr \/>10\\<wbr \/>Include\\<wbr \/>10.0.20348.0\\<wbr \/>um\\<wbr \/>shlobj_core.h(236,1): error C2872: 'IUnknown': ambiguous symbol\r\n(compiling source file 'Widget.cpp')\r\n    D:\\Program Files (x86)\\<wbr \/>Windows Kits\\<wbr \/>10\\<wbr \/>Include\\<wbr \/>10.0.20348.0\\<wbr \/>um\\<wbr \/>unknwnbase.h(117,9):\r\n        could be 'IUnknown'\r\n    D:\\Program Files (x86)\\<wbr \/>Windows Kits\\<wbr \/>10\\<wbr \/>Include\\<wbr \/>10.0.20348.0\\<wbr \/>cppwinrt\\<wbr \/>winrt\\<wbr \/>base.h(312,12):\r\n    or       'winrt::Windows::Foundation::IUnknown'\r\n\r\n(repeat a gazillion more times)\r\n<\/pre>\n<p>The compiler says that the problem is with <code>shlobj_core.h<\/code>, but really, that&#8217;s just where the problem was discovered.<\/p>\n<p>The offending line in <code>shlobj_core.h<\/code> is<\/p>\n<pre>DECLARE_INTERFACE_IID_(IExtractIconA, <span style=\"border: solid 1px currentcolor;\">IUnknown<\/span>, \"000214eb-0000-0000-c000-000000000046\")\r\n<\/pre>\n<p>The <code>DECLARE_<wbr \/>INTERFACE_<wbr \/>IID_<\/code> macro expands to<\/p>\n<pre>struct __declspec(uuid(000214eb-0000-0000-c000-000000000046\"))\r\n      __declspec(novtable) IExtractIconA : public IUnknown\r\n<\/pre>\n<p>The compiler reports a problem with the name <code>IUnknown<\/code> that is being used as the base class because it is ambiguous. It could refer to <code>IUnknown<\/code> (in the global namespace) or <code>winrt::<wbr \/>Windows::<wbr \/>Foundation::<wbr \/>IUnknown<\/code>.<\/p>\n<p>But wait, how could <code>IUnknown<\/code>, when referenced from the global namespace, end up referring to a name in namespace scope?<\/p>\n<p>Answer: If the name has been imported into the global namespace via a <code>using<\/code> directive.\u00b9<\/p>\n<p>After some searching, they found a header file that contained the line<\/p>\n<pre>using namespace winrt::Windows::Foundation;\r\n<\/pre>\n<p>This imports all of <code>winrt::<wbr \/>Windows::<wbr \/>Foundation<\/code> into the global namespace, and that&#8217;s creating the name collision.<\/p>\n<p>Putting <code>using namespace<\/code> directives in header files goes against <a title=\"SF.7: Don't write using namespace at global scope in a header file\" href=\"https:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#sf7-dont-write-using-namespace-at-global-scope-in-a-header-file\"> SF.7: Don&#8217;t write using namespace at global scope in a header file<\/a>.<\/p>\n<p>Instead, qualify the names in the header file. Yes, this makes things wordy, but it&#8217;s better than polluting the global namespace.<\/p>\n<p>Importing names into the global namespace should either be scoped or performed from the main C++ file rather than any headers.<\/p>\n<p>\u00b9 Another possible answer is &#8220;If the namespace has been added to the search via argument-dependent lookup.&#8221; However, this particular usage is not as a function call, so argument-dependent lookup does not apply, seeing as there are no arguments.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Finding out why multiple entities with the same name are visible.<\/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-111285","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Finding out why multiple entities with the same name are visible.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111285","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=111285"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111285\/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=111285"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=111285"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=111285"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}