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.
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
"A problem well stated is a problem half solved.” - Charles F. Kettering
Re: Where does a template function get instantiated ?
Originally Posted by John E
I guess that kinda makes sense if template functions are effectively inlined... or is there some other explanation
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.
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?
"A problem well stated is a problem half solved.” - Charles F. Kettering
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
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
. . .
Re: Where does a template function get instantiated ?
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?
I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.
This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.
Re: Where does a template function get instantiated ?
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>
staticinline 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:
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:
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:-
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
Or am I over-thinking this??
"A problem well stated is a problem half solved.” - Charles F. Kettering
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.
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".
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.
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>;
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.
Last edited by OReubens; October 21st, 2013 at 07:52 AM.
Re: Where does a template function get instantiated ?
[Edit...] Read in conjunction with my next post
Thanks for such a comprehensive response O'Reubens. BTW...
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);
};
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.
There's still something about this that I'm failing to understand...
[Edit...] further info in next post !
Last edited by John E; October 21st, 2013 at 12:23 PM.
"A problem well stated is a problem half solved.” - Charles F. Kettering
Re: Where does a template function get instantiated ?
Originally Posted by John E
There's still something about this that I'm failing to understand...
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)
"A problem well stated is a problem half solved.” - Charles F. Kettering
Re: Where does a template function get instantiated ?
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.
Re: Where does a template function get instantiated ?
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'.
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.
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.
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 ?
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.
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.
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.
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.
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.
* The Best Reasons to Target Windows 8
Learn some of the best reasons why you should seriously consider bringing your Android mobile development expertise to bear on the Windows 8 platform.