Reputation: 923
In C++03 we have template explicit instantiation definitions (template class Foo<int>
) which force instantiation of a template class.
In C++11 we've got template explicit instantiation declarations (extern template class Foo<int>
) which should prevent implicit instantiations of a template class. (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 T>
class Foo
{
T inst;
public:
Foo(T i);
T& get() const;
};
//Foo.cpp
#include "stdafx.h"
#include "Foo.h"
template<class T>
Foo<T>::Foo(T inst) : inst(inst) { }
template<class T>
T& Foo<T>::get() const { return inst; }
template class Foo<int>; //explicit instantiation definition
//test1.h
#pragma once
#include "Foo.h"
//This line does not work
//extern template class Foo<int>; //explicit instantiation declaration.
void baz();
//test1.cpp
#include "stdafx.h"
#include "test1.h"
void baz()
{
Foo<int> foo(10);
int i = foo.get();
}
The result does not depend on whether I comment (extern template class Foo<int>;
) 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<int>::Foo<int>(int)
and int Foo<int>::get(void)const
marked as UNDEF in test1.obj which means that they must be resolved elsewhere (i.e. Foo was compiled only ONCE).
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<int> foo(10); //implicit instantiation of Foo<int>
int i = foo.get();
}
//test2.h
#pragma once
#include "Foo.h"
extern template class Foo<int>;
void bar();
//test2.cpp
#include "stdafx.h"
#include "test2.h"
void bar()
{
Foo<int> foo(10); //should refer to Foo<int> 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.
Upvotes: 4
Views: 1586
Reputation: 923
Here is a good explanation why the ATTEMP#2 does not work as I want: Is there a bug with extern template in Visual C++?
In short when you define and implement the template in header file the compiler may inline it. And then it does the explicit instantiation definition doesn't work by standart (14.7.2/10 "Explicit instantiation").
So we need to force the compiler to NOT inline the template. For example by implementing it just after the declaration.
template<class T>
class Foo {
...
T get() const;
};
template<class T>
T Foo<T>::get() const
{ ... }
Upvotes: 0