Friday 10 November 2017

C++11 extern templates: where do we actually need them?

In C++03 we have template explicit
instantiation definitions
(template class
Foo
) which force instantiation of a template class.




In C++11 we've got
template explicit instantiation declarations
(extern template class Foo) which should prevent
implicit instantiations of a template class. ( href="http://en.cppreference.com/w/cpp/language/class_template" rel="nofollow">Class
template instantiation)



I'm trying to
simulate the situation where I actually needed the explicit instantiation declaration in
order to reduce compilation time. But I can't. Looks like everything works without this
feature (or doesn't work with it).



Here is an
example:



//Foo.h
#pragma
once
template
class
Foo

{
T inst;
public:
Foo(T
i);
T& get()
const;
};


//Foo.cpp
#include
"stdafx.h"

#include "Foo.h"

template T>
Foo::Foo(T inst) : inst(inst) {
}

template
T& Foo::get()
const { return inst; }

template class Foo; //explicit
instantiation
definition



//test1.h
#pragma
once
#include "Foo.h"

//This line does not
work
//extern template class Foo; //explicit instantiation
declaration.

void
baz();



//test1.cpp
#include
"stdafx.h"
#include "test1.h"

void
baz()
{
Foo foo(10);
int i =
foo.get();
}



The
result does not depend on whether I comment
(extern template class Foo;) line or
not.



Here is symbols of both *.obj
files:




dumpbin
/SYMBOLS test1.obj



011 00000000 UNDEF notype
() External | ??0?$Foo@H@@QAE@H@Z (public: __thiscall
Foo::Foo(int))'




012 00000000 UNDEF
notype () External | ?get@?$Foo@H@@QBEHXZ (public: int __thiscall Foo::get(void)const
)



013 00000000 SECT4 notype () External |
?baz@@YAXXZ (void __cdecl baz(void))




...



dumpbin /SYMBOLS
Foo.obj



017 00000000 SECT4 notype () External
| ??0?$Foo@H@@QAE@H@Z (public: __thiscall Foo::Foo(int))





018 00000000 SECT6 notype () External | ?get@?$Foo@H@@QBEHXZ
(public: int __thiscall Foo::get(void)const
)




Pay attention
what Foo::Foo(int) and int
Foo::get(void)const
marked as UNDEF
in test1.obj which means that they must be resolved elsewhere (i.e. Foo was compiled
only ONCE).



ATTEMP
#2:



If I define full template in Foo.h file
(without explicit instantiation definition) then
extern template doesn't help - template compiles twice (in both
test1.cpp and
test2.cpp).




Example:



//test1.h
#pragma
once
#include "Foo.h"
void
baz();


//test1.cpp

#include
"stdafx.h"
#include "test1.h"
void baz()
{

Foo foo(10); //implicit instantiation of Foo
int i =
foo.get();
}


//test2.h

#pragma
once
#include "Foo.h"
extern template class
Foo;
void
bar();


//test2.cpp
#include
"stdafx.h"
#include "test2.h"
void
bar()

{
Foo foo(10); //should refer to
Foo from test1.obj but IT IS NOT
int i =
foo.get();
}


Here
are symbol dumps:





dumpbin /SYMBOLS test2.obj





01D 00000000 SECT4 notype () External | ??0?$Foo@H@@QAE@H@Z (public: __thiscall
Foo::Foo(int))



01E 00000000 SECT8 notype ()
External | ?get@?$Foo@H@@QBEHXZ (public: int __thiscall Foo::get(void)const
)



01F 00000000 SECT6 notype () External |
?bar@@YAXXZ (void __cdecl bar(void))



dumpbin
/SYMBOLS test1.obj



01D 00000000 SECT6 notype
() External | ?baz@@YAXXZ (void __cdecl baz(void))





01E 00000000 SECT4 notype () External | ??0?$Foo@H@@QAE@H@Z
(public: __thiscall Foo::Foo(int))



01F
00000000 SECT8 notype () External | ?get@?$Foo@H@@QBEHXZ (public: int __thiscall
Foo::get(void)const
)




In both *.obj
files Foo presents.



So my question is in what
may be the usefulness of the explicit instantiation declarations? Or maybe I miss
something in my tests?




I use VS2013
compiler.

No comments:

Post a Comment

php - file_get_contents shows unexpected output while reading a file

I want to output an inline jpg image as a base64 encoded string, however when I do this : $contents = file_get_contents($filename); print &q...