-
Where does a template function get instantiated ?
Consider the following code:
Code:
template<class TYPE>
void MultiplyByTwo(TYPE data)
{
cout <<"Double = " << data * 2 << endl;
}
If I declared that code in a header file I'd be able to call it with an int, float, double or whatever. But where does the actual code get instantiated? Is it effectively inlined?
What I'm wondering is if there'd ever be any scenario for putting such code in a DLL - e.g.
Code:
#ifdef BUILDING_MY_DLL
#define MY_DLL_API __declspec(dllexport)
#else
#define MY_DLL_API __declspec(dllimport)
#endif
template<class TYPE>
MY_DLL_API void MultiplyByTwo(TYPE data)
{
cout <<"Double = " << data * 2 << endl;
}
I just tried it and was slightly surprised to find it wouldn't compile. It compiles fine when actually building the DLL but when I try to build something else which uses that DLL I get compiler error C2491 (definition of dllimport function not allowed).
I guess that kinda makes sense if template functions are effectively inlined... or is there some other explanation :confused:
-
Re: Where does a template function get instantiated ?
Quote:
Originally Posted by
John E
I guess that kinda makes sense if template functions are effectively inlined... or is there some other explanation :confused:
Templates are just that -- templates. The template is not an actual function -- all it does is describe a generic boilerplate for a function. So it makes no sense placing it in a DLL, since it isn't a function at all.
The function only becomes alive when an instantiation of that template is done. Then the compiler does what it does to create a concrete function. Whether it is inline or not depends on the compiler and compiler options.
Regards,
Paul McKenzie
-
Re: Where does a template function get instantiated ?
Thanks Paul. Here's the scenario I'm trying to get my head around...
Suppose some template code needed to access a static variable. How would I make sure that there was only one physical copy of the variable? If I put the code into a DLL that usually guarantees that there'll only be one copy - even if the DLL links to several other modules. But that only really works for regular functions. So is it bad practise for either an inline function or a template to access static data?
-
Re: Where does a template function get instantiated ?
Quote:
Originally Posted by
John E
What I'm wondering is if there'd ever be any scenario for putting such code in a DLL - e.g.
Code:
#ifdef BUILDING_MY_DLL
#define MY_DLL_API __declspec(dllexport)
#else
#define MY_DLL_API __declspec(dllimport)
#endif
template<class TYPE>
MY_DLL_API void MultiplyByTwo(TYPE data)
{
cout <<"Double = " << data * 2 << endl;
}
I just tried it and was slightly surprised to find it wouldn't compile. It compiles fine when actually building the DLL but when I try to build something else which uses that DLL I get compiler error C2491 (definition of dllimport function not allowed).
I guess that kinda makes sense if template functions are effectively inlined... or is there some other explanation :confused:
John, this particular compile error has nothing to do neither with templates nor dlls. It is exactly what the error message says: definition of dllimport function not allowed. Which means, dllimport is applicable for declarations only, and never is for definitions.
Just consider a plain sample with no template, no dll.
Code:
// 96.cpp
#include <iostream>
using namespace std;
__declspec(dllimport) void MultiplyByTwo(int data)
{
cout <<"Double = " << data * 2 << endl;
}
int main()
{
MultiplyByTwo(2);
return 0;
}
Code:
D:\Temp\96>cl 96.cpp /EHsc
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
96.cpp
96.cpp(7) : error C2491: 'MultiplyByTwo' : definition of dllimport function not allowed
You see that? The same story, absolutely. So your "demo" proves effectively nothing, and there was nothing to be surprised about.
And inlining again has nothing to do with templates.
Code:
#include <iostream>
using namespace std;
template<class TYPE>
void MultiplyByTwo(TYPE data)
{
cout <<"Double = " << data * 2 << endl;
}
template<class TYPE>
inline void MultiplyByThree(TYPE data)
{
cout <<"Triple = " << data * 3 << endl;
}
int main()
{
int a = 2;
MultiplyByTwo(a);
MultiplyByThree(a);
return 0;
}
Code:
D:\Temp\96>cl 96a.cpp /EHsc /link /map:96a.map
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
96a.cpp
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
/out:96a.exe
/map:96a.map
96a.obj
D:\Temp\96>96a.exe
Double = 4
Triple = 6
But anyway compiler decided not to inline.
Code:
96a
Timestamp is 52618590 (Fri Oct 18 23:01:36 2013)
Preferred load address is 00400000
Start Length Name Class
0001:00000000 00017afaH .text CODE
0001:00017b00 0000056cH .text$x CODE
. . .
0003:00000000 00001780H .data DATA
0003:00001780 0000210cH .bss DATA
Address Publics by Value Rva+Base Lib:Object
0000:00000000 __except_list 00000000 <absolute>
0000:00000022 ___safe_se_handler_count 00000022 <absolute>
0000:00000000 ___ImageBase 00400000 <linker-defined>
0001:00000000 _main 00401000 f 96a.obj
0001:00000030 ??$MultiplyByTwo@H@@YAXH@Z 00401030 f i 96a.obj
0001:00000060 ?endl@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@1@AAV21@@Z 00401060 f i 96a.obj
0001:00000080 ?put@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV12@D@Z 00401080 f i 96a.obj
0001:000001b0 ?eq_int_type@?$char_traits@D@std@@SA_NABH0@Z 004011b0 f i 96a.obj
0001:000001d0 ?eof@?$char_traits@D@std@@SAHXZ 004011d0 f i 96a.obj
0001:000001e0 ?flush@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV12@XZ 004011e0 f i 96a.obj
. . .
0001:00000a20 ??0_Sentry_base@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAE@AAV12@@Z 00401a20 f i 96a.obj
0001:00000a80 ??1_Sentry_base@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAE@XZ 00401a80 f i 96a.obj
0001:00000ad0 ??$MultiplyByThree@H@@YAXH@Z 00401ad0 f i 96a.obj
0001:00000b10 ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV01@AAV01@@Z@Z 00401b10 f i 96a.obj
0001:00000b30 ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z 00401b30 f i 96a.obj
. . .
Precisely like Paul already said.
-
Re: Where does a template function get instantiated ?
>> Suppose some template code needed to access a static variable.
Could export the variable. Or provide an accessor function to it.
Instantiated templates can also be exported, but may not be very useful.
http://msdn.microsoft.com/en-us/library/twa2aw10.aspx
gg
-
Re: Where does a template function get instantiated ?
Quote:
Originally Posted by
Igor Vartanov
[...]
But anyway compiler decided not to inline.
Code:
96a
Timestamp is 52618590 (Fri Oct 18 23:01:36 2013)
Preferred load address is 00400000
Start Length Name Class
0001:00000000 00017afaH .text CODE
0001:00017b00 0000056cH .text$x CODE
. . .
0003:00000000 00001780H .data DATA
0003:00001780 0000210cH .bss DATA
Address Publics by Value Rva+Base Lib:Object
0000:00000000 __except_list 00000000 <absolute>
0000:00000022 ___safe_se_handler_count 00000022 <absolute>
0000:00000000 ___ImageBase 00400000 <linker-defined>
0001:00000000 _main 00401000 f 96a.obj
0001:00000030 ??$MultiplyByTwo@H@@YAXH@Z 00401030 f i 96a.obj
0001:00000060 ?endl@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@1@AAV21@@Z 00401060 f i 96a.obj
0001:00000080 ?put@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV12@D@Z 00401080 f i 96a.obj
0001:000001b0 ?eq_int_type@?$char_traits@D@std@@SA_NABH0@Z 004011b0 f i 96a.obj
0001:000001d0 ?eof@?$char_traits@D@std@@SAHXZ 004011d0 f i 96a.obj
0001:000001e0 ?flush@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV12@XZ 004011e0 f i 96a.obj
. . .
0001:00000a20 ??0_Sentry_base@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAE@AAV12@@Z 00401a20 f i 96a.obj
0001:00000a80 ??1_Sentry_base@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAE@XZ 00401a80 f i 96a.obj
0001:00000ad0 ??$MultiplyByThree@H@@YAXH@Z 00401ad0 f i 96a.obj
0001:00000b10 ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV01@AAV01@@Z@Z 00401b10 f i 96a.obj
0001:00000b30 ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z 00401b30 f i 96a.obj
. . .
Precisely like Paul already said.
I don't think the map file really proves anything here in that respect: Your sample functions are non-static free functions, so they're visible to code outside the module defining them. The compiler must provide non-inlined exported versions of the functions, just in case any code in another module decides to call them. (Inlineness can't be exported of course.) The compiler may still inline calls to these functions made from inside the module defining them. What does the assembly listing say?
-
Re: Where does a template function get instantiated ?
Quote:
Originally Posted by
Eri523
I don't think the map file really proves anything here in that respect: Your sample functions are non-static free functions, so they're visible to code outside the module defining them. The compiler must provide non-inlined exported versions of the functions, just in case any code in another module decides to call them. (Inlineness can't be exported of course.) The compiler may still inline calls to these functions made from inside the module defining them. What does the assembly listing say?
Please be my guest. :)
Code:
#include <iostream>
using namespace std;
template<class TYPE>
static void MultiplyByTwo(TYPE data)
{
cout <<"Double = " << data * 2 << endl;
}
template<class TYPE>
static inline void MultiplyByThree(TYPE data)
{
cout <<"Triple = " << data * 3 << endl;
}
int main()
{
int a = 2;
MultiplyByTwo(a);
MultiplyByThree(a);
return 0;
}
Code:
D:\Temp\96>cl 96b.cpp /EHsc /link /map:96b.map
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
96b.cpp
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
/out:96b.exe
/map:96b.map
96b.obj
D:\Temp\96>grep Multiply 96b.map
96b.map: 0001:00000030 ??$MultiplyByTwo@H@@YAXH@Z 00401030 f 96b.obj
96b.map: 0001:00000060 ??$MultiplyByThree@H@@YAXH@Z 00401060 f 96b.obj
-
Re: Where does a template function get instantiated ?
Hmmm...
When I compile that (VC++ 2010 Express, default release mode settings except for turning on assembly listing and map file output), both function calls do get inlined:
Code:
PUBLIC _main
; Function compile flags: /Ogtp
; COMDAT _main
_TEXT SEGMENT
_main PROC ; COMDAT
; 19 : int a = 2;
; 20 : MultiplyByTwo(a);
00000 a1 00 00 00 00 mov eax, DWORD PTR __imp_?endl@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@1@AAV21@@Z
00005 8b 0d 00 00 00
00 mov ecx, DWORD PTR __imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A
0000b 50 push eax
0000c 6a 04 push 4
0000e 68 00 00 00 00 push OFFSET ??_C@_0L@IAJJIPJN@Double?5?$DN?5?5?$AA@
00013 51 push ecx
00014 e8 00 00 00 00 call ??$?6U?$char_traits@D@std@@@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@PBD@Z ; std::operator<<<std::char_traits<char> >
00019 83 c4 08 add esp, 8
0001c 8b c8 mov ecx, eax
0001e ff 15 00 00 00
00 call DWORD PTR __imp_??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z
00024 8b c8 mov ecx, eax
00026 ff 15 00 00 00
00 call DWORD PTR __imp_??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV01@AAV01@@Z@Z
; 21 : MultiplyByThree(a);
0002c 8b 15 00 00 00
00 mov edx, DWORD PTR __imp_?endl@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@1@AAV21@@Z
00032 a1 00 00 00 00 mov eax, DWORD PTR __imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A
00037 52 push edx
00038 6a 06 push 6
0003a 68 00 00 00 00 push OFFSET ??_C@_0L@IIFFMGDN@Triple?5?$DN?5?5?$AA@
0003f 50 push eax
00040 e8 00 00 00 00 call ??$?6U?$char_traits@D@std@@@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@PBD@Z ; std::operator<<<std::char_traits<char> >
00045 83 c4 08 add esp, 8
00048 8b c8 mov ecx, eax
0004a ff 15 00 00 00
00 call DWORD PTR __imp_??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z
00050 8b c8 mov ecx, eax
00052 ff 15 00 00 00
00 call DWORD PTR __imp_??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV01@AAV01@@Z@Z
; 22 :
; 23 : return 0;
00058 33 c0 xor eax, eax
; 24 : }
0005a c3 ret 0
_main ENDP
_TEXT ENDS
END
For reasons I don't know, despite the static, the compiler output still contains non-inlined versions of the functions that I dodn't see being called anywhere:
Code:
; Function compile flags: /Ogtp
; File c:\users\eri\documents\visual studio 2010\projects\test12\test12\test12.cpp
; COMDAT ??$MultiplyByThree@H@@YAXH@Z
_TEXT SEGMENT
??$MultiplyByThree@H@@YAXH@Z PROC ; MultiplyByThree<int>, COMDAT
; 14 : cout <<"Triple = " << data * 3 << endl;
00000 a1 00 00 00 00 mov eax, DWORD PTR __imp_?endl@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@1@AAV21@@Z
00005 8b 0d 00 00 00
00 mov ecx, DWORD PTR __imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A
0000b 50 push eax
0000c 6a 06 push 6
0000e 68 00 00 00 00 push OFFSET ??_C@_0L@IIFFMGDN@Triple?5?$DN?5?5?$AA@
00013 51 push ecx
00014 e8 00 00 00 00 call ??$?6U?$char_traits@D@std@@@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@PBD@Z ; std::operator<<<std::char_traits<char> >
00019 83 c4 08 add esp, 8
0001c 8b c8 mov ecx, eax
0001e ff 15 00 00 00
00 call DWORD PTR __imp_??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z
00024 8b c8 mov ecx, eax
00026 ff 15 00 00 00
00 call DWORD PTR __imp_??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV01@AAV01@@Z@Z
; 15 : }
0002c c3 ret 0
??$MultiplyByThree@H@@YAXH@Z ENDP ; MultiplyByThree<int>
; Function compile flags: /Ogtp
_TEXT ENDS
; COMDAT ??$MultiplyByTwo@H@@YAXH@Z
_TEXT SEGMENT
??$MultiplyByTwo@H@@YAXH@Z PROC ; MultiplyByTwo<int>, COMDAT
; 8 : cout <<"Double = " << data * 2 << endl;
00000 a1 00 00 00 00 mov eax, DWORD PTR __imp_?endl@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@1@AAV21@@Z
00005 8b 0d 00 00 00
00 mov ecx, DWORD PTR __imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A
0000b 50 push eax
0000c 6a 04 push 4
0000e 68 00 00 00 00 push OFFSET ??_C@_0L@IAJJIPJN@Double?5?$DN?5?5?$AA@
00013 51 push ecx
00014 e8 00 00 00 00 call ??$?6U?$char_traits@D@std@@@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@PBD@Z ; std::operator<<<std::char_traits<char> >
00019 83 c4 08 add esp, 8
0001c 8b c8 mov ecx, eax
0001e ff 15 00 00 00
00 call DWORD PTR __imp_??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z
00024 8b c8 mov ecx, eax
00026 ff 15 00 00 00
00 call DWORD PTR __imp_??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV01@AAV01@@Z@Z
; 9 : }
0002c c3 ret 0
??$MultiplyByTwo@H@@YAXH@Z ENDP ; MultiplyByTwo<int>
_TEXT ENDS
They don't show up in the map file, though.
-
Re: Where does a template function get instantiated ?
Thanks for all the suggestions guys. The problem has morphed somewhat during the past couple of days. My earlier problem (how to make sure the template function only had one instance of a static data member) has gone away now, since I can use an accessor function, like Codeplug suggested. But I still need to figure out where exactly template functions get instantiated.
Basically I'm trying to convert some code that was originally written for gcc. To boil it down to its simplest level the code builds 2 x DLLs. The source code for one DLL contains all the templates (let's call it DLLA) but the other one (DLLB) seems to use them. Here's what the code originally looked like:-
Code:
// This template is in DLL A
namespace DLLA {
template<typename Time>
class Event {
public:
Event (EventType type=0, Time time=0, uint32_t size=0, uint8_t* buf=NULL, bool alloc=false);
Event(const Event& copy, bool alloc);
~Event();
const Event& operator=(const Event& copy);
void set(const uint8_t* buf, uint32_t size, Time t);
// Blah blah blah. loads of other stuff
};
}
The parameter Time can be one of several types (int, double, int64_t etc). Which types are needed isn't known until we build DLL B:-
Code:
// These functions are in DLL B
void func_A (DLLA::Event<double>& a_event);
void func_B (DLLA::Event<inr>& b_event);
void func_C (DLLA::Event<int64_t>& c_event);
If I build the code without any modification, DLL B has no access to DLLA::Event. Nothing got exported from DLL A so they all come up as unresolved externals. If DLL::Event wasn't a template class this would be the quickest way to solve the problem:-
Code:
namespace DLLA {
class DLLA_API Event {
public:
Event (EventType type=0, int time=0, uint32_t size=0, uint8_t* buf=NULL, bool alloc=false);
Event (EventType type=0, double time=0, uint32_t size=0, uint8_t* buf=NULL, bool alloc=false);
Event (EventType type=0, int64_t time=0, uint32_t size=0, uint8_t* buf=NULL, bool alloc=false);
Event(const Event& copy, bool alloc);
~Event();
const Event& operator=(const Event& copy);
void set(const uint8_t* buf, uint32_t size, int t);
void set(const uint8_t* buf, uint32_t size, double t);
void set(const uint8_t* buf, uint32_t size, int64_t t);
// Blah blah blah. loads of other stuff
};
}
(assume that DLLA_API will import or export the symbols, as required). So you might imagine that this would work for a template class:-
Code:
namespace DLLA {
template<typename Time>
class DLLA_API Event {
public:
Event (EventType type=0, Time time=0, uint32_t size=0, uint8_t* buf=NULL, bool alloc=false);
Event(const Event& copy, bool alloc);
~Event();
const Event& operator=(const Event& copy);
void set(const uint8_t* buf, uint32_t size, Time t);
// Blah blah blah. loads of other stuff
};
}
but unfortunately, it doesn't... :cry:
This does seem to work....
Code:
namespace DLLA {
template<typename Time>
class Event {
public:
DLLA_API Event (EventType type=0, Time time=0, uint32_t size=0, uint8_t* buf=NULL, bool alloc=false);
DLLA_API Event(const Event& copy, bool alloc);
DLLA_API ~Event();
DLLA_API const Event& operator=(const Event& copy);
DLLA_API void set(const uint8_t* buf, uint32_t size, Time t);
// Blah blah blah. loads of other stuff
};
}
At least, both DLLs will compile and link. I haven't got as far as testing them yet. So if the worst comes to the worst, it looks like I can make this work by specifically exporting any required symbols from DLL A (BTW, the actual functions are implemented in a cpp source file in DLLA). But when building DLL A, how does it know that sometime subsequently, it's going to need classes which deal with double, int and int64_t? When building DLL A, surely the compiler won't know that as it hasn't encountered DLL B's code yet :confused:
Or am I over-thinking this??
-
Re: Where does a template function get instantiated ?
The reality behind it.
Templates get instantiated as part of the code module currently being compiled. A linker would then remove duplicates from the objects being linked together. modern compilers however tend to postpone the actual instantiation to a pre-linking stage when they know what template instances are needed. THis assumes the compiler and linker "work together" on generating code.
If you define a template as part of the set of headers and classes that make up a DLL project. Then those templates will get instantiated as part of the DLL code if and only if you use the template in the dll's code.
If you use the template in an application using the headers of the dll, then the template will be instantiated again in the code for your application. This could cause a link failure if the dll doesn't export the necessary members.
You either accept the above as a given, and this is exactly what you want.
OR. you export explicit instantiations of the templates from the DLL, and then assume only those instantiations are being used outside the DLL. In that case, the DLL will have code for the explicit instantiations (even if nobody ends up using them, just like any other function/class in the dll). And the exe can written to make use of the explicit instantiations from the DLL rather than reinstantiating them.
Note that a template doesn't export anything. A template is a "shortcut to create some code" (not really, but maybe the analogy will help). a dll can only export actual instantiations of anything.
as to the "is it going to be inline" question.
This is up to the compiler and compiler settings. the template could be expanded "inline", or could be instantiated in the exe's code, with a call generated to it. It won't ever be a call to code in the dll, unless you explicitely call to a dll exported instance.
Quote:
Basically I'm trying to convert some code that was originally written for gcc. To boil it down to its simplest level the code builds 2 x DLLs. The source code for one DLL contains all the templates (let's call it DLLA) but the other one (DLLB) seems to use them. Here's what the code originally looked like:-
a DLL doesn't "contain" templates. This is a wrong view to things just as saying that a "DLL contains headers".
While the project of a dll may define headers. They could just as well not be part of the DLL project and just be located in a unrelated directory somewhere. headers don't generate code. (or you're doing it wrong)
it's using the stuff from a header that may generate code. headers are just definitions, none of which formally end up as part of a DLL or EXE image. They're "stuff the compiler needs to validate the source".
Quote:
If I build the code without any modification, DLL B has no access to DLLA::Event. Nothing got exported from DLL A so they all come up as unresolved externals. If DLL::Event wasn't a template class this would be the quickest way to solve the problem:-
from what I can see, that's because the template class only has function prototypes. Not the implementation of them. The implementation is usually "inlined" as part of the header, or listed outside the header after the class definition or it's part of a separate file you need to include as well as the header.
if dll B says DLLA:Event<double> it doesn't know how to instantiate this because the implementation isn't available. It also can't call into DLLA because the specific Event<double> type memberfunctions aren't being exported from DLLA.
Quote:
class DLLA_API Event {
OK, this is half the work. you now have told the compiler that it should locate the members of Event<something> in A.DLL and generate calls to it.
but you now also need to explicitely instantiate the Event<type> members for each type you're expecting to be used.
there's no way around it, either the consumer of the template instantiates, or the producer does (but then the producer needs to instantiate all types).
assuming you want to export the types.
create a source in dll A with the explicit template instantiations you want to export.
Code:
#include <event.h>
// instantiate the types we want to support in this DLL for exporting
template class DLLA:Event<int>;
template class DLLA:Event<int64>;
template class DLLA:Event<double>;
Quote:
DLLA_API Event (EventType...
This isn't any different than the above, so I'm confused why this would work and the other wouldn't. Are you sure this actually does work ? an export definition at the class level is just "lasy mode" for doing the same on every member.
-
Re: Where does a template function get instantiated ?
[Edit...] Read in conjunction with my next post :o
Thanks for such a comprehensive response O'Reubens. BTW...
Quote:
Originally Posted by
OReubens
This isn't any different than the above, so I'm confused why this would work and the other wouldn't. Are you sure this actually does work ? an export definition at the class level is just "lasy mode" for doing the same on every member.
Yes, I think you're right about that. I must have had the misfortune to pick one particular example that didn't work for some reason. All the others I've tried today have worked fine. Here's what I'm struggling to understand now...
Code:
/// Class that stores exceptions thrown from different threads
class LIBAUDIOGRAPHER_API ThreaderException : public Exception
{
public:
template<typename T>
ThreaderException (T const & thrower, std::exception const & e)
: Exception (thrower,
boost::str ( boost::format
("\n\t- Dynamic type: %1%\n\t- what(): %2%")
% DebugUtils::demangled_name (e) % e.what() ))
{ }
};
If I have the above in a header file, as it's originally written (still getting compiled into DLL A) I find that DLL B reports that the symbol ThreadException is an unresolved external. So now I re-jig it to use the more conventional header file and cpp file - i.e.
Code:
HEADER FILE:
/// Class that stores exceptions thrown from different threads
class LIBAUDIOGRAPHER_API ThreaderException : public Exception
{
public:
template<typename T>
ThreaderException (T const & thrower, std::exception const & e);
};
Code:
CPP FILE:
template<typename T>
ThreaderException::ThreaderException (T const & thrower, std::exception const & e)
: Exception (thrower,
boost::str ( boost::format
("\n\t- Dynamic type: %1%\n\t- what(): %2%")
% DebugUtils::demangled_name (e) % e.what() ))
{
}
This time, DLL B links successfully to DLL A. This suggests that a concrete instantiation of ThreaderException gets exported from DLL A and DLL B can now find it.
BUT...
ThreadException objects are getting created (in DLL B) with different types of thrower. None of these were known at the time I compiled and linked DLL A. So if the compiler is using the template to create concrete instances of ThreadException (for all the different types of thrower) how can it do that when I build DLL A? At that point, it doesn't know how many types are going to be needed. :confused:
There's still something about this that I'm failing to understand... :cry:
[Edit...] further info in next post !
-
Re: Where does a template function get instantiated ?
Quote:
Originally Posted by
John E
There's still something about this that I'm failing to understand... :cry:
I think I'm slowly getting this. Here's what I had at first....
Code:
/// Class that stores exceptions thrown from different threads
class LIBAUDIOGRAPHER_API ThreaderException : public Exception
{
public:
template<typename T>
ThreaderException (T const & thrower, std::exception const & e)
: Exception (thrower,
boost::str ( boost::format
("\n\t- Dynamic type: %1%\n\t- what(): %2%")
% DebugUtils::demangled_name (e) % e.what() ))
{ }
};
If I simply take out the __declspec specifier (LIBAUDIOGRAPHER_API) I can then link DLL B to DLL A without any apparent issues.
So.... am I right in thinking that:-
a) A template class or function must be completely implemented in its header file (i.e. not with simple declarations which then get implemented in a separate source file) ?
b) Template classes (and presumably functions) must not be declared as __declspec(dllexport) / (import) ?
c) If a template function accesses static data it must do so via an accessor function ? (given that we don't know where precisely the template function will get instantiated)
-
Re: Where does a template function get instantiated ?
Quote:
Originally Posted by
John E
a) A template class or function must be completely implemented in its header file (i.e. not with simple declarations which then get implemented in a separate source file) ?
That is the case without DLL's. Templates must be accompanied by its implementation within the same source module.
The template implementation can be inlined within the template class, or outside the class in a separate file that gets #included directly after the template class. But regardless, the template and implementation must appear together in one unit.
Regards,
Paul McKenzie
-
Re: Where does a template function get instantiated ?
Thanks Paul (and thanks everyone else!) I think this is finally starting to make some sense :thumb:
-
Re: Where does a template function get instantiated ?
One more question...
If a template function needs to access static data, this should get done via an accessor function as previously discussed. But what about template classes? Is it considered bad practice (or at least very risky) for a template class to have static data members?
-
Re: Where does a template function get instantiated ?
Quote:
Originally Posted by
John E
Is it considered bad practice (or at least very risky) for a template class to have static data members?
When you have multi-module projects, it is risky, template class or concrete class, to have static data members. This is the case especially if you rely on the static data being initialized at the point where you're accessing the static data.
The rules of C++ for when static data members are guaranteed to be initialized get complex (at least to me they are). If you have the entire program in a single module, static initialization becomes easy. It's when you're dealing with multi-module programs where it becomes risky.
Here is a link to such a scenario:
http://www.parashift.com/c++-faq/static-init-order.html
I have also seen static members declared in other modules to not be initialized after main() is called.
Regards,
Paul McKenzie
-
1 Attachment(s)
Re: Where does a template function get instantiated ?
Quote:
Originally Posted by
John E
If I simply take out the __declspec specifier (LIBAUDIOGRAPHER_API) I can then link DLL B to DLL A without any apparent issues.
So.... am I right in thinking that:-
Well, are you sure you link B to A? Or just seeing those compile with no error? Please don't be misguided by your non-template C++ experience. In case the template function can be resolved, no matter by means of object file or library (including import library), the function generation won't occur. But in the opposite case it will, and this may result in code copies made by the same template but in different binary modules. When you remove __declspec from class declaration, it's very probable that you just have one copy per dll. I afraid this is not what they call 'linked'.
Quote:
a) A template class or function must be completely implemented in its header file (i.e. not with simple declarations which then get implemented in a separate source file) ?
Not necessarily. As Paul said, you must have full template-related code in the scope of the same compile unit, but the template parts may be spread out in different files. See the attached archive, case direct.
Quote:
b) Template classes (and presumably functions) must not be declared as __declspec(dllexport) / (import) ?
Not necessarily, see the case import. The dll is built instantiating and exporting particular classes. In case client wants those particular classes to link with, and template class declaration does not produce definitions with dllimport (remember your previous trouble with C2491), the class is imported alright.
Quote:
c) If a template function accesses static data it must do so via an accessor function ? (given that we don't know where precisely the template function will get instantiated)
The static data not necessarily must be accessed via accessor function, and the data itself is going to reside where it was instructed to be, specifically in the module where the template static data has been defined. See the case static.
-
Re: Where does a template function get instantiated ?
Hi Igor, thanks for providing those projects for me. I wasn't able to use your makefiles as I'm building with VC2005 so I just built a very simple VC project and added the source files. [Edit...] Oops, I stand corrected. They aren't makefiles - just normal batch files!! :blush:
So far I've only built your direct example (which I built as a console project). What's interesting is that your batch files build just fine - but if I try to build in a VC project I get this linker error....
Quote:
97a2.obj : error LNK2019: unresolved external symbol "public: void __thiscall A<unsigned int>::out2(unsigned int &)" (?out2@?$A@I@@QAEXAAI@Z) referenced in function "void __cdecl foo(void)" (?foo@@YAXXZ)
To remove the error I needed to copy the template for void A<T>::out2(T& val) so that it's in 97a2.cpp, as well as 97a1.cpp - i.e. this code needs to be in BOTH cpp files:-
Code:
template<class T>
void A<T>::out2(T& val)
{
std::cout << val << " (" << __FUNCTION__ << ")\n";
}
Only by having them both can the linker find one instantiation for int and the other one for unsigned.
So (at least in the direct example) it seems like the best approach is to keep all the template code in a header file.
-
Re: Where does a template function get instantiated ?
Quote:
Originally Posted by
John E
So (at least in the direct example) it seems like the best approach is to keep all the template code in a header file.
This is what I stated all along. The entire template implementation must be visible to wherever you're instantiating the template.
Also, when you created the solution, did you add the template implementation as one of the source files to compile? If you did, then that was wrong. You don't add the template implementation as a separate source module to be compiled. You #include that module at the end of the template class so that again, the entire implementation is together.
Here is an example:
Template.h:
Code:
#ifndef TEMPLATE_H
#define TEMPLATE_H
template <typename T>
class SomeClass
{
public:
void DoSomething(T x);
};
#include "template.inl"
#endif
Here is template.inl:
Code:
template <typename T>
void SomeClass<T>::DoSomething(T x)
{
}
This is an example of breaking up the template so that the implementation is outside the class. However look at the header file -- it #includes the implementation. The template.inl file is not a separate compilation unit that you add to your project to compile.
Regards,
Paul McKenzie
-
1 Attachment(s)
Re: Where does a template function get instantiated ?
Quote:
Originally Posted by
Paul McKenzie
This is what I stated all along. The entire template implementation must be visible to wherever you're instantiating the template.
Hi Paul. Please don't think I was doubting your advice. That's absolutely NOT the case!
Anyway... I know you guys are busy but if anyone gets a chance, please could they take a look at the attached zip file for me? It contains Igor's original source files + a batch file to build them (called make2.bat) + my own MSVC project and solution.
In theory, my project should be equivalent to Igor's batch file - and yet Igor's file builds without any problems whereas my project gives an unresolved external. I'm really curious to know what the difference is.
-
Re: Where does a template function get instantiated ?
Quote:
Originally Posted by
John E
I think I'm slowly getting this. Here's what I had at first....
Code:
/// Class that stores exceptions thrown from different threads
class LIBAUDIOGRAPHER_API ThreaderException : public Exception
{
public:
template<typename T>
ThreaderException (T const & thrower, std::exception const & e)
: Exception (thrower,
boost::str ( boost::format
("\n\t- Dynamic type: %1%\n\t- what(): %2%")
% DebugUtils::demangled_name (e) % e.what() ))
{ }
};
If I simply take out the __declspec specifier (LIBAUDIOGRAPHER_API) I can then link DLL B to DLL A without any apparent issues.
THis isn't the problem you originally talked about.
THis is a regular exported class, with a templated function. That's not quite the same as a templated class.
In the above it also includes implementation (the empty {}) So this template is "instantiable" anywhere the above is included, and for "any type".
So yes, this will compile, with the compiler instantiating the memberfunction in the code using the templated constructor.
It may cause a link issue if not everything this instantiation needs (such as access to a matching Exception constructor) is available/accessible in DLL B.
Quote:
a) A template class or function must be completely implemented in its header file (i.e. not with simple declarations which then get implemented in a separate source file) ?
No. This isn't correct.
While this is the common practice, because it IS necessary if you want it to work for every possible type you pass to the template parameter. It is not necessary or it could even be undesired.
In the DLL case, having the implementation in the header (or in an included file) it means the template will be instantiated in every other dll/exe that uses the template. So you end up with a lot of duplicate code.
This could be what you want. It could also be the very thing you're trying to avoid.
If you want to make available a template, have it's implementation/code be part of a dll and be exported so other dlls/exes merely call into the dll rather than instantiating. THis is possible with the restriction that the exporting DLL must explicitely instantiate every possible variant of the template parameters you wish to support. This is the only way to make sure the dll actually does have the code you're expecting the other dlls/exes to call into.
Quote:
b) Template classes (and presumably functions) must not be declared as __declspec(dllexport) / (import) ?
This depends on what you're trying to do. If you with to make available the template, and allow in-situ instantiations. THen no. This is the case for all the STL. (and most of boost)
If you're trying to have a "generic code" dll that other dll's/exe's call into then it is needed. (and in that case, you must provide for the code actually being in said dll and be exported.
Quote:
c) If a template function accesses static data it must do so via an accessor function ? (given that we don't know where precisely the template function will get instantiated)
Again... depends on what you want to do.
An accessor isn't needed, but may be necesary in some cases (such as when you're using late-loading which doesn't support data member access).
It again depends on the case... do you want the data to be in the dll, or do you want it in each dll/exe (possibly even being different in each dll/exe).
If the static data is member of a templated class. and you want the data to be in the dll...
then again, you'll need to explicitely instantiate the class for every possible type you want to support.
Quote:
This is what I stated all along. The entire template implementation must be visible to wherever you're instantiating the template.
This is correct, but doesn't imply the implementation needs to be in the header.
It is perfectly possible to have part of it in .cpp files, but that means you'll be restricted in where you can instantiate (all of) the template, or use those specific member functions at least.
Typically speaking... Suppose...
Template.h defines a class template, and defines most of the implementation, except the implementation of the foo() function.
-> You can use the template class anywhere in so far as you don't call foo() because the compiler can't instantiate a foo() function for any type. It'll insert a call to the specific class<T>::foo() so compilation will proceed, and you'll get a linker error because this specific function could not be found.
-> Template.cpp defines the foo() generic template.
This changes nothing to the above, because the generic template doesn't cause any instantiations on it's own.
-> Template.cpp however CAN contain other code that uses foo() if those are instantiations, this causes the class<T>::foo() to be in the object for the used types T. So now the foo() used in other sources will link as well (but only for the types used in template.cpp).
-> if Template.cpp doesn't define a generic template, but instead defines specializations.
then you can call the foo() from any other source in the dll (and it'll link) but only for the types you specialized.
Now... ALl of the above assumes just a single dll/exe. Things become a bit more complex when exporting is involved. Lots more combinations and possibilities to take into account. Again, the big question being... Do you want the consumers of the template to instantiate. Or do you want the instantiation to only be in the dll.
-
Re: Where does a template function get instantiated ?
a simple analogy that may explain things (it's not how things actually work, but bear with me).
Code:
#include <mydll.h>
int main()
{
MyDllClass<int> x;
x.DoSomething();
return 0;
}
Do you want this to mean:
"replace the x.DoSomething() with the entire body of code that is the DoSomething function specialized for type int."
If yes, then that's a normal template (like std::vector and std::string), the implementation needs to be in the header or an include, so the compiler can actually do this "replacing".
Or do you want this to mean:
"do a call to MyDllClass<int>::DoSomething() that is assumed to be exported from MyDll.dll"
In this case, you need to export the template, and instantiate MyDllClass<int> in the dll.
Where the function implementations are is now irrelevant. Having them in the header or in a .cpp of the MyDll project.
If you want it to mean "do a replace for some types and a call for some other types".
That is possible too, but it'll take quite a bit of fiddling and messing with macro's. Unless you truely understand the above two first, I wouldn't dive into this :-)
-
Re: Where does a template function get instantiated ?
Quote:
Originally Posted by
John E
In theory, my project should be equivalent to Igor's batch file - and yet Igor's file builds without any problems whereas my project gives an unresolved external. I'm really curious to know what the difference is.
Well, make2.bat was intended precisely to demonstrate linkage error, i.e. to see the difference between make and make2, what incomplete template specification looks like from compiler/linker perspective. :)
Code:
J:\Temp\templates-dlls-static-data\direct>make.bat
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
97a1.cpp
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
/out:97a1.exe
97a1.obj
J:\Temp\templates-dlls-static-data\direct>make2.bat
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
97a1.cpp
97a2.cpp
Generating Code...
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
/out:97a1.exe
97a1.obj
97a2.obj
97a2.obj : error LNK2019: unresolved external symbol "public: void __thiscall A<unsigned int>::out2(unsigned int &)" (?out2@?$A@I@@QAEXAAI@Z) referenced in function "void __cdecl foo(void)" (?foo@@YAXXZ)
97a1.exe : fatal error LNK1120: 1 unresolved externals
-
Re: Where does a template function get instantiated ?
Quote:
Originally Posted by
Igor Vartanov
Well, make2.bat was intended precisely to demonstrate linkage error. :)
Code:
97a2.obj : error LNK2019: unresolved external symbol "public: void __thiscall A<unsigned int>::out2(unsigned int &)" (?out2@?$A@I@@QAEXAAI@Z) referenced in function "void __cdecl foo(void)" (?foo@@YAXXZ)
97a1.exe : fatal error LNK1120: 1 unresolved externals
Doh! I must have run your make2.bat after fixing the linkage error! No wonder it seemed okay... :blush:
-
Re: Where does a template function get instantiated ?
Hi Igor. While studying your import example I came across an interesting variation which I thought you'd like to know about. Here's the code you originally wrote for the DLL side....
Code:
#include <iostream>
#include "97a.h"
// Templates for our required functions (will get instantiated later)
template<class T>
void A<T>::out1(T& val)
{
std::cout << val << " (" << __FUNCTION__ << ")\n";
}
template<class T>
void A<T>::out2(T& val)
{
std::cout << val << " (" << __FUNCTION__ << ")\n";
}
// Instantiation (makes sure that we create a specific function to handle each required data type)
template<class T>
class Compiletime
{
public:
void instantiate(T t)
{
A<T> at;
at.out1(t);
at.out2(t);
}
};
struct _Init
{
_Init()
{
Compiletime<int>().instantiate(1);
#ifdef FOO
Compiletime<unsigned>().instantiate(1);
#endif
}
} Init;
Note there are 2 stages to the initialization. In the _Init struct I need to call Compiletime::instantiate() for each type where I'll need a set of handler functions. Then in Compiletime::instantiate() I need to create an object of the requested type AND call each of its functions (note the lines in blue). If I eliminate the blue lines, those functions end up not getting created. However, I found I could do the whole in one easier stage -namely:-
Code:
#include <iostream>
#include "97a.h"
// Template functions as they were originally
template<class T>
void A<T>::out1(T& val)
{
std::cout << val << " (" << __FUNCTION__ << ")\n";
}
template<class T>
void A<T>::out2(T& val)
{
std::cout << val << " (" << __FUNCTION__ << ")\n";
}
// New initialization
template class A<int>;
template class A<unsigned>;
Note that I still need to specify each type that I need to handle - but I don't need to call any actual functions. I'm not sure if my new method has any drawbacks (lack of portability??) but it seems to be working for me with MSVC. :thumb:
-
Re: Where does a template function get instantiated ?
Quote:
Originally Posted by
John E
I'm not sure if my new method has any drawbacks
it has. Explicit instantiation definition of a class ( eg "template class foo<int>;" ) forces the compiler to instantiate all of its non template members. For example, given a class template
Code:
template< class T >
struct A
{
void foo() { typename T::some_type bar; /* ... */ }
};
// this compiles
int main() { A<int> a; }
// this does not
template class A<int>;
this may change the semantics of a class template, because the usual "lazy" instantiation behavior can be exploited to customize its behavior depending on the instantiating types. For example, a wrapper class template may define a copy costructor intended to be used only when also T has one ( as a concrete example, std::tuple<T1,..> is movable if and only if T1,... are ).
of course, you can still explicitly instantiate specific members instead.
-
Re: Where does a template function get instantiated ?
Quote:
Originally Posted by
John E
// Instantiation (makes sure that we create a specific function to handle each required data type)
The drawback here is that this approach generates extra code that gets executed which is unnecessary.
Quote:
Note that I still need to specify each type that I need to handle - but I don't need to call any actual functions. I'm not sure if my new method has any drawbacks (lack of portability??) but it seems to be working for me with MSVC. :thumb:
This is explicit instantiation and is part of the C++ standard. It will work on all ansi c++ compilers.
I mentioned you needed to do this in #10 (last code section) for this precise reason. (to make sure the compiler generated the class instances for the explicit types).
This makes the compiler generate the code for the class with the specified type, but not generate any calls to it (other than any explicit calls you have elsewhere).
Quote:
it has. Explicit instantiation definition of a class ( eg "template class foo<int>;" ) forces the compiler to instantiate all of its non template members. For example, given a class template
This is precisely what it is supposed to do, so it's hardly a drawback. You need to generate ALL of the code for ALL of the member functions, because the dll can't know which members will get actually called.
You're even wrong in your assertion, because not only the non-template members get instantiated, ALL members get instantiated, the template members get instantiated for the specific type.
This is different from a pure 'inline' template class where only the actually accessed members will end up in the code. due to optimisation stripping the rest out.
AGain, this isn't any different from having a regular non-templated class. If you export from a dll, the compiler will need to add all the members in the dll because it can't know which ones will get called in the dlls/exes using the dll.
The only good reason for doing this kind of explicit instantiation is in library code and dll's. So I wouldn't call it a drawback, rather it's the means to achieve the goal of having the instantiations.
For the same reason, the "lazy behaviour" is a moot argument, since you wouldn't even want to or be able to export a template class instance from a dll with a specific type if the instantiation isn't possible.
-
Re: Where does a template function get instantiated ?
Quote:
Originally Posted by
OReubens
You're even wrong in your assertion, because not only the non-template members get instantiated, ALL members get instantiated, the template members get instantiated for the specific type.
I'm not; template members of a class template are not instantiated ( how could they ? ) with an explicit instantiation definition. As an example, consider the "template<class U,class V> std:: pair( U&&,V&&)" forwarding constructors. I repeat, I said <template members> of a <class template>.
Quote:
Originally Posted by
OReubens
This is precisely what it is supposed to do, so it's hardly a drawback [...] For the same reason, the "lazy behaviour" is a moot argument, since you wouldn't even want to or be able to export a template class instance from a dll with a specific type if the instantiation isn't possible.
no, template classes are often designed to allow some members to be ill formed for some types that do not support certain specific operations. Again, consider the std:: pair<T,W> default constructor, it will give an error when instantiated if T or W have no default constructor. This makes std:: pair default contructible when ( and only when ) its parameters are. Now, try explicitly instantiating an std:: pair for non default contructible parameters ... so, it's defintely a drawback for many class templates.
-
Re: Where does a template function get instantiated ?
Quote:
Originally Posted by
OReubens
I mentioned you needed to do this in #10 (last code section) for this precise reason. (to make sure the compiler generated the class instances for the explicit types).
Doh! So you did. I must have missed that at the time.
I wasted 6 days figuring out what you'd already told me... :blush:
-
Re: Where does a template function get instantiated ?
Quote:
Originally Posted by
superbonzo
I'm not; template members of a class template are not instantiated ( how could they ? ) with an explicit instantiation definition. As an example, consider the "template<class U,class V> std:: pair( U&&,V&&)" forwarding constructors. I repeat, I said <template members> of a <class template>.
ok, looks like I misunderstood you.
But the reasoning I made still holds regardless. You can't EXPORT an 'open template definition'. You can put the definition in the header, but then that isn't exporting. In that case the instatiation (for the given type) will happen in every exe/dll you are building you are using that header (= duplicate code).
Quote:
no, template classes are often designed to allow some members to be ill formed for some types that do not support certain specific operations. Again, consider the std:: pair<T,W> default constructor, it will give an error when instantiated if T or W have no default constructor. This makes std:: pair default contructible when ( and only when ) its parameters are. Now, try explicitly instantiating an std:: pair for non default contructible parameters ... so, it's defintely a drawback for many class templates.
True, but then you wouldn't want (nor could you) EXPORT such classes for specific template types if they aren't instantiable from a dll.
It's what I have been saying all along. Either you provide the template definition in the header (or an include) in which case you could end up with duplicate code in every exe/dll.
Or you EXPORT the class (or members) from a DLL in which case you can only do that by explicit instantiating the types in the DLL.
If you really really know what you're doing, you can even make some sort of hybrid in between where you export the template for a certain number of types (wich code in the dll) and still allow custom types (instantiated in the compiled module). But there's rarely a need to even go that route.