Re: Where does a template function get instantiated ?
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.
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 ?
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!!
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....
97a2.obj : error LNK2019: unresolved external symbol "public: void __thiscall A<unsigned int>:ut2(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>:ut2(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:-
Re: Where does a template function get instantiated ?
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.
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.
Re: Where does a template function get instantiated ?
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.
"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 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.
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 ?
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
Last edited by Igor Vartanov; October 22nd, 2013 at 09:25 AM.
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.
"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'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 ?
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.
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.
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).
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 ?
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>.
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 ?
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...
"A problem well stated is a problem half solved.” - Charles F. Kettering
Re: Where does a template function get instantiated ?
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).
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.
* 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.