A colleague added another header file to their project, and everything started blowing up with “ambiguous symbol” errors.
#include "pch.h"
#include "something.h"
#include "newheader.h"
#include <shlobj.h>
...
This resulted in a build error in Visual Studio:
D:\Program Files (x86)\Windows Kits\ 10\ Include\ 10.0.20348.0\ um\ shlobj_core.h(236,1): error C2872: 'IUnknown': ambiguous symbol (compiling source file 'Widget.cpp') D:\Program Files (x86)\ Windows Kits\ 10\ Include\ 10.0.20348.0\ um\ unknwnbase.h(117,9): could be 'IUnknown' D:\Program Files (x86)\ Windows Kits\ 10\ Include\ 10.0.20348.0\ cppwinrt\ winrt\ base.h(312,12): or 'winrt::Windows::Foundation::IUnknown' (repeat a gazillion more times)
The compiler says that the problem is with shlobj_core.h
, but really, that’s just where the problem was discovered.
The offending line in shlobj_core.h
is
DECLARE_INTERFACE_IID_(IExtractIconA, IUnknown, "000214eb-0000-0000-c000-000000000046")
The DECLARE_
macro expands to
struct __declspec(uuid(000214eb-0000-0000-c000-000000000046")) __declspec(novtable) IExtractIconA : public IUnknown
The compiler reports a problem with the name IUnknown
that is being used as the base class because it is ambiguous. It could refer to IUnknown
(in the global namespace) or winrt::
.
But wait, how could IUnknown
, when referenced from the global namespace, end up referring to a name in namespace scope?
Answer: If the name has been imported into the global namespace via a using
directive.¹
After some searching, they found a header file that contained the line
using namespace winrt::Windows::Foundation;
This imports all of winrt::
into the global namespace, and that’s creating the name collision.
Putting using namespace
directives in header files goes against SF.7: Don’t write using namespace at global scope in a header file.
Instead, qualify the names in the header file. Yes, this makes things wordy, but it’s better than polluting the global namespace.
Importing names into the global namespace should either be scoped or performed from the main C++ file rather than any headers.
¹ Another possible answer is “If the namespace has been added to the search via argument-dependent lookup.” However, this particular usage is not as a function call, so argument-dependent lookup does not apply, seeing as there are no arguments.
0 comments
Be the first to start the discussion.