CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 2 of 2 FirstFirst 12
Results 16 to 30 of 30
  1. #16
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Where does a template function get instantiated ?

    Quote Originally Posted by John E View Post
    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
    Last edited by Paul McKenzie; October 21st, 2013 at 01:31 PM.

  2. #17
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: Where does a template function get instantiated ?

    Quote Originally Posted by John E View Post
    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.
    Attached Files Attached Files
    Best regards,
    Igor

  3. #18
    John E is offline Elite Member Power Poster
    Join Date
    Apr 2001
    Location
    Manchester, England
    Posts
    4,835

    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:-

    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.
    Last edited by John E; October 22nd, 2013 at 05:36 AM.
    "A problem well stated is a problem half solved.” - Charles F. Kettering

  4. #19
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Where does a template function get instantiated ?

    Quote Originally Posted by John E View Post
    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

  5. #20
    John E is offline Elite Member Power Poster
    Join Date
    Apr 2001
    Location
    Manchester, England
    Posts
    4,835

    Re: Where does a template function get instantiated ?

    Quote Originally Posted by Paul McKenzie View Post
    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.
    Attached Files Attached Files
    "A problem well stated is a problem half solved.” - Charles F. Kettering

  6. #21
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: Where does a template function get instantiated ?

    Quote Originally Posted by John E View Post
    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.

  7. #22
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    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 :-)

  8. #23
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: Where does a template function get instantiated ?

    Quote Originally Posted by John E View Post
    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.
    Best regards,
    Igor

  9. #24
    John E is offline Elite Member Power Poster
    Join Date
    Apr 2001
    Location
    Manchester, England
    Posts
    4,835

    Re: Where does a template function get instantiated ?

    Quote Originally Posted by Igor Vartanov View Post
    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...
    "A problem well stated is a problem half solved.” - Charles F. Kettering

  10. #25
    John E is offline Elite Member Power Poster
    Join Date
    Apr 2001
    Location
    Manchester, England
    Posts
    4,835

    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

  11. #26
    Join Date
    Oct 2008
    Posts
    1,456

    Re: Where does a template function get instantiated ?

    Quote Originally Posted by John E View Post
    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.

  12. #27
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: Where does a template function get instantiated ?

    Quote Originally Posted by John E View Post
    // 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.

  13. #28
    Join Date
    Oct 2008
    Posts
    1,456

    Re: Where does a template function get instantiated ?

    Quote Originally Posted by OReubens View Post
    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 View Post
    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.

  14. #29
    John E is offline Elite Member Power Poster
    Join Date
    Apr 2001
    Location
    Manchester, England
    Posts
    4,835

    Re: Where does a template function get instantiated ?

    Quote Originally Posted by OReubens View Post
    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

  15. #30
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: Where does a template function get instantiated ?

    Quote Originally Posted by superbonzo View Post
    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.

Page 2 of 2 FirstFirst 12

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured