After #import
ing a .tlb file, I tried to use one of the generated _com_ptr_t
objects in a function template. This works fine if the functions I use are also used outside of a function template. However if it's only used in a function template, I get a link error.
Can anyone explain why this happens? I'm guessing it's to do with template instantiation but I'm not sure how the #import
mechanism works.
Is it the expected behaviour?
Here's a minimal example which includes all combinations according to the value of COMPILE_OPTION
.
- Define only the regular function that uses the object (causing it to be instantiated)
- Define only the function template (which doesn't cause the used function to be instantiated) - This is the problem case
- Define both, this shows that if the object is used in a regular function the template option works as expected (and not as in case #2)
Code:
#import <mshtml.tlb>
#if COMPILE_OPTION & 1
int foo(MSHTML::IHTMLElementPtr elem) {
return elem->tagName.length();
}
#endif
#if COMPILE_OPTION & 2
template <class T>
int bar(T elem) {
return elem->tagName.length();
}
#endif
int main() {
#if COMPILE_OPTION & 2
bar(MSHTML::IHTMLElementPtr());
#else
foo(MSHTML::IHTMLElementPtr());
#endif
}
Now the following compile successfully:
cl Source.cpp /DCOMPILE_OPTION=1
cl Source.cpp /DCOMPILE_OPTION=3
But this one:
cl Source.cpp /DCOMPILE_OPTION=2
Produces the following (relevant error in bold):
Source.obj : error LNK2019: unresolved external symbol "public: class _bstr_t __thiscall MSHTML::IHTMLElement::GettagName(void)" (?GettagName@IHTMLElement@MSHTML@@QAE?AV_bstr_t@@XZ) referenced in function "int __cdecl bar<class _com_ptr_t<class _com_IIID<struct MSHTML::IHTMLElement,&struct __s_GUID const _GUID_3050f1ff_98b5_11cf_bb82_00aa00bdce0b> > >(class _com_ptr_t<class _com_IIID<struct MSHTML::IHTMLElement,&struct __s_GUID const _GUID_3050f1ff_98b5_11cf_bb82_00aa00bdce0b> >)" (??$bar@V?$_com_ptr_t@V?$_com_IIID@UIHTMLElement@MSHTML@@$1?_GUID_3050f1ff_98b5_11cf_bb82_00aa00bdce0b@@3U__s_GUID@@B@@@@@@YAHV?$_com_ptr_t@V?$_com_IIID@UIHTMLElement@MSHTML@@$1?_GUID_3050f1ff_98b5_11cf_bb82_00aa00bdce0b@@3U__s_GUID@@B@@@@@Z)
Source.exe : fatal error LNK1120: 1 unresolved externals
Notes:
- A workaround is to use the raw COM methods
- This is obviously a simplified version, the reason I'm using a template is that I'm using a library that has several types with common functionality that don't share a common base interface.