How to do explicit template instantiation correctly? - c++

I'm using templates for implementing the CRTP pattern. With the code below I'm getting linker errors (for all the methods that are defined in the base class CPConnectionBase) like this:
error LNK2001: unresolved external symbol "public: void __thiscall CPConnectionBase::start(void)" (?start#?$CPConnectionBase#VTNCPConnection####QAEXXZ)
I guess the solution here is explicit template instantiation. And indeed I can build my code when I add
#include "TNCPConnection.h"
template class CPConnectionBase<TNCPConnection>;
to the file CPConnectionBase.cpp. This is certainly the wrong place since I don't want to include the header of all possible derived classes into the source of the base class (I might want to use the base class also in another project with other derived classes).
So my goal is to instantiate the template in the source file of the derived class (TNCPConnection.h or TNCPConnection.cpp), but I couldn't find a solution. Adding
template class CPConnectionBase<TNCPConnection>;
to the file TNCPConnection.cpp does not solve my linker problems, and adding
template<> class CPConnectionBase<TNCPConnection>;
to the file TNCPConnection.cpp gives me a compile time error:
error C2908: explicit specialization; 'CPConnectionBase' has already been instantiated
How can I get rid of the linker errors without making the implementation of the base class dependent of the header files of the derived classes?
Here is the skeleton of my code:
CPConnectionBase.h
template <class Derived>
class CPConnectionBase : public boost::enable_shared_from_this<Derived>
{
public:
void start();
};
CPConnectionBase.cpp
#include "stdafx.h"
#include "CPConnectionBase.h"
template<class Derived>
void CPConnectionBase<Derived>::start()
{
...
}
TNCPConnection.h
#include "CPConnectionBase.h"
class TNCPConnection : public CPConnectionBase<TNCPConnection>
{
public:
void foo(void);
};
TNCPConnection.cpp
#include "stdafx.h"
#include "TNCPConnection.h"
void TNCPConnection::foo(void)
{
...
}

The definition of CPConnectionBase::start() must be available at the place where you explicitly instantiate the class - otherwise the function will not be instantiated, and this non-instantiation happens silently (with linker errors following).
The standard solution is a header CPConnectionBase.hpp that defines the template functions declared in CPConnectionBase.h. Include CPConnectionBase.hpp in TNCPConnection.cpp and explicitly instantiate there.

I should add a note here:
MSVC allows to declare the explicit specialization before the member functions, inside the same compilation unit.
GCC (4.7) requires them to be at the end of the file.
I.e.
MSVC:
template class TClass<Base>;
template <class T> void TClass<T>::Function() {}
GCC:
template <class T> void TClass<T>::Function() {}
template class TClass<Base>;

First, I'd suggest renaming CPConnectionBase.cpp to CPConnectionBase.inl, as it doesn't contain any non-template code.
At the point where you instantiate the template, you need to #include <CPConnectionBase.inl> first. I'd suggest doing it in TNCPConnection.cpp.
Alternatively, you can move the CPConnectionBase implementation to the the CPConnectionBase.h header file, and the compiler will handle the instantiation automatically.

move the templated code from the .cpp to the header.
When you include a header with templates, the templated code is genereated in the target code according to what it finds in the header.
If the code is in the .cpp file it can't be found and thus cant be generated (because you only included the .h)

You could also use the "Seperation Model". Just define the template in one file, and mark that
definition with the keyword export:
export template <class Derived>
class CPConnectionBase : public boost::enable_shared_from_this<Derived>
{
public:
void start();
};

Related

How does template class instantiation work together with class inheritance?

Code
I have the following snippets of 2 classes with a separate source and header file. The derived class is a template class.
handler.h
class BaseHandler {
public:
BaseHandler(){}
BaseHandler(const std::string& directive);
virtual ~BaseHandler();
virtual bool operator()();
private:
const std::string m_directive;
};
template<typename C>
class DirectiveHandler : public BaseHandler {
public:
DirectiveHandler(const std::string& directive);
~DirectiveHandler();
bool operator()() override;
private:
std::vector<C> m_configurations;
};
handler.cpp
#include "handler.h"
BaseHandler::BaseHandler(const std::string& directive) : m_directive(directive) {};
BaseHandler::~BaseHandler(){};
template<typename C>
DirectiveHandler<C>::DirectiveHandler(const std::string& directive) :
BaseHandler(directive) {};
template<typename C>
bool DirectiveHandler<C>::operator()(){ return true; };
main.cpp
#include "handler.h"
template class DirectiveHandler<double>; //explicit template instantiation
int main(int argc, char *argv[]){
....
To my understanding I need to instantiate the template after it has been defined, this can happen either implicitly (leave out template class DirectiveHandler<double>;) or explicitly.
I'm assuming that implicit instantiation fails due to the separation of definition and declaration in the respective source and header file.
With the snippet of main.cpp above I have the following warnings:
warning: explicit template instantiation DirectiveHandler<double> will emit a vtable in every translation unit
warning: instantiation of function DirectiveHandler<double>::operator() required here, but no definition available
If change template class DirectiveHandler<double> to extern template class DirectiveHandler<double>;both warnings dissapear. I do understand why warning 2 is cleared, because the template class resides in handler.cpp. I fail to see how it clears warning 1 as well.
Question
Why does the addition of the extern keyword clear warning 1 (see above)?
I assume, you are compiling your code with CLang? (To the best of my knowledge, it is CLang warning, unless g++ started to emit it as well).
On any rate, the answer to the question as asked (I only have to assume that OP understands everything else) is the simple fact that template class DirectiveHandler<double>; - which is implicit template instantiation definition, which produces vtbls and such. (The fact that the warning is emitted for .cpp file might be actually a bug, but OP doesn't ask about it).
On the other hand, extern template class DirectiveHandler<double>; is not a definition. It is a declaration, which doesn't on itself trigger vptr's generation - and thus you see no warning.

How do I resolve placing template specializations before "instantiation" with GCC

I have a set of templates where each base template has some large specializations and many of the other methods are mainly casts around types and constructors and operator=(). I made templates to factor out all those little methods as inlines and put the fat ones in the CPP files for a shared library. In windows it compiles and links fine into a DLL. It all does what I want on MSC but on GCC with the specialization code in the C++ file many of the specializations occur "after instantiation" with GCC.
Structurally the code is like the below. (the real case is more messy) I'm not sure what I need to do as the template method declarations that call their superclass methods (from other templates) are where the method code is "instantiated" for their superclass templates. What I need to do is somehow defer the instantiation until after the header declarations to happen in the .cpp file where the specialization's method bodies for the library are compiled.
// header file .h
template<class SubClassT, class CharT>
class XBaseT
: public YBaseT<char_object<CharT>>
{
typedef XBaseT<XObject,CharT> super;
public:
typedef char_object<CharT> ObjT; // seen by subclasses
inline XBaseT() {}
inline XBaseT(ObjT &p); // note no body, then intention is to have this specialization in library, not header.
...
};
template<>
class XClass<XObject>
: public XBaseT<XObject,char>
{
typedef XBaseT<XObject,char> super;
public:
inline XClass() {}
inline XClass(ObjT &p) : super(p) {}
...
};
template<>
class XObject
: public ContainerT<XObject>
{
typedef ContainerT<XObject> super;
public:
inline XObject() {}
static ContainerT<XObject> *static create(InitStruct &is);
...
};
// specializations in cpp file
tenplate<>
ContainerT<XObject> *
create(InitStruct &is) {
// big code here needs to be in CPP file for library
}
// specialization for <XObject,char> happens "after instantiation" even thoght the method in it's template class is declared with no body.
template<>
XBaseT<XObject, char>::XBaseT(ObjT *p) {
p_ = XObject::create(p);
}
The specialization just above in the.cpp file barfs on GCC as it is "after instantiation",
The instantiation in GCC happens when the "inline XClass(ObjT *p) : super(p) {}" constructor in XClass is declared. And that is so tiny I would like it to be inline as it should optimize out to nothing. On MSC the code is not instantiated until explicitly done so in the .cpp file. and the with MSC the linker seems to sort out what is needed and the compiler warns of missing methods declared but NOT instantiated there. In a declaration of
template class XBaseT;
template class ContainerT;
template class XClass;
The issues is some of the methods specialized for these templates are dependent on more than one of the templates and the specializations need to happen after the declarations.
How do I using "typename" or other template features get this for compile and link under CCC as opposed to windows MSC ?

Inheritance and conversion between 2 classes failed c++

I have class Signal and Image and both classes have method with same name but different input parameters and output parameter. Is is allowed?
template <class T> class Signal {
public:
Signal<T> zeroPadding(Signal<T>);
}
template <class T> class Image:public Signal<T>
{
public:
Image(void);
~Image(void);
Image(int,int);
Image(int,int,double);
Image(int,int,double,double);
Signal<T> zeroPadding(Image<T>);
template <class T> Image<T>::Image(int width,int height):Signal(width,height) {}
template <class T> Image<T>::Image(int width,int height,double dt):Signal(width,height,dt) {}
template <class T> Image<T>::Image(int width,int height,double dt,double t0 ):Signal(width,height,dt,t0) {}
template <class T> Signal<T> Image<T>::zeroPadding(Image<T> im2){
Image<T> i1 =(*this);
Image<T> i2 =im2;
if (i1.getHeight()==i2.getHeight()){
....
return(im2);
}
}
}
int main() {
Image<int> *a=new Image<int>(2,3);
Image<int> *b=new Image<int>(1,3);
(*a).zeroPadding(*b); //when I try to debug it failed with error error LNK2019:
//unresolved external symbol
//"public: __thiscall Signal<int>::~Signal<int>(void)" (??1?$Signal#H##QAE#XZ)
//referenced in function
//"public: __thiscall Image<int>::~Image<int>(void)" (??1?$Image#H##QAE#XZ)
}
Another question: What about if I want to call in main function (*a).Signal::zeroPadding(*b) how I can convert (*a) and (*b) to be Signal?
Because of how the linker works with templates, your implementation should be on the same file as the declaration. You get LNK2019 because the method is only declared but not defined, the compiler doesn't know what to do with it.
Conversion is possible. You need to explicitly cast a pointer to a or b as Signal.
Yes, it is allowed. If member functions are not declared as virtual, then the functions to be called are determined by the caller's class. In your case, The zeroPadding function is being called by Image type which is the derivative class, so the functions in the Image class will overload the base class.
And your error message
unresolved external symbol
public: __thiscall Signal<int>::~Signal<int>(void)" (??1?$Signal#H##QAE#XZ)referenced in function
public: __thiscall Image<int>::~Image<int>(void)" (??1?$Image#H##QAE#XZ)
implies that you have declared the destructor for Signal and Image template class, but didn't implement them, so there will be a link error;
And for your last question, since *a and *b are the derivative class instances of class Signal, so you can convert them to Signal at ease. Every simple methods of type casting will do that.static_cast<Signal<int> >(*a) or directly use (Signal)(*a) is enough.
Update: Seems like that this is a very old but common met issue about seperate compilation. :)
What is seperate compilation? An easy way to explain, if you put your implementation codes in a different source file with the declaration file in writing a template class, then you are using seperate compilation. There is a keyword export specifically for this scenario, but the compiler support isn't that good.
Suggestion is that to put the implementation codes together into the declaration file or maybe include the implementation file into the header file for template class.
Templates and separate compilation
http://www.cs.uofs.edu/~bi/se516/chapter4/tsld022.htm
http://www.cplusplus.com/forum/beginner/73735/

explicit template instantiation: MSVC vs. GCC

I'm trying to deal with namespaces & templates in C++. I can get the following code to compile in MSVC (no warnings or errors), but am having no luck at all with various permutations with CYGWIN/GCC. Any help would be appreciated.
In the header file I declare a templated subclass as follows:
#include <gdal.h>
namespace sfms {
template <class _type, GDALDataType _gdal> class SmfsGrid_Typed : public SfmsGrid_Base {
public:
SmfsGrid_Typed();
SmfsGrid_Typed(const SmfsGrid_Typed<_type, _gdal> *toCopy);
SmfsGrid_Typed(std::string filename);
virtual ~SmfsGrid_Typed();
virtual bool OpenRead();
virtual bool OpenWrite();
protected:
_type m_nodata_value;
virtual SfmsGrid_Base *New() const;
virtual SfmsGrid_Base *New(SfmsGrid_Base *toCopy) const;
virtual void initCopy(SfmsGrid_Base *copy) const;
};
template SmfsGrid_Typed<double, GDT_Float64>;
template SmfsGrid_Typed<float, GDT_Float32>;
template SmfsGrid_Typed<int, GDT_Int32>;
typedef SmfsGrid_Typed<double, GDT_Float64> SmfsGrid_Double;
typedef SmfsGrid_Typed<float, GDT_Float32> SmfsGrid_Float;
typedef SmfsGrid_Typed<int, GDT_Int32> SmfsGrid_Int;
}
In the source file I instantiate the specialized template class as follows:
void hi_there() {
//...
sfms::SmfsGrid_Typed<int, GDT_Int32> *grid = new sfms::SmfsGrid_Typed<int, GDT_Int32>(filey);
//...
sfms::SmfsGrid_Int *grid2 = new sfms::SmfsGrid_Int(filey);
//...
}
GDALDataType is an enum, but that doesn't seem to the the issue.
I've tried the class declaration inside and outside the namespace, with no success.
The source file containing the implementations for the templates compile okay with both compilers.
I've tried dropping the explicit template instantation and including the relevant C++ source file, also with no joy.
I've tried 'template', 'typename' and 'typedef' keywords in various different places (in the templated class def'n and where I try to create the object) with no success, but various interesting and often misleading error messages with GCC, such as:
error: 'SmfsGrid_Typed' is not a member of 'sfms'
when it clearly is! :) Regardless, any help on porting this code from MSVC to GCC would help.
Thanks!
Your explicit template instantiation looks wrong. Try replacing it with
template class SmfsGrid_Typed<double, GDT_Float64>;
template class SmfsGrid_Typed<float, GDT_Float32>;
template class SmfsGrid_Typed<int, GDT_Int32>;
(Note the added class keyword)

Inheriting from a virtual template class in C++

How do I inherit from a virtual template class, in this code:
// test.h
class Base {
public:
virtual std::string Foo() = 0;
virtual std::string Bar() = 0;
};
template <typename T>
class Derived : public Base {
public:
Derived(const T& data) : data_(data) { }
virtual std::string Foo();
virtual std::string Bar();
T data() {
return data_;
}
private:
T data_;
};
typedef Derived<std::string> DStr;
typedef Derived<int> DInt;
// test.cpp
template<typename T>
std::string Derived<T>::Foo() { ... }
template<typename T>
std::string Derived<T>::Bar() { ... }
When I try to use the DStr or DInt, the linker complain that there are unresolved externals, which are Derived<std::string>::Foo() and Derived<std::string>::Bar(), and the same for Derived<int>.
Did I miss something in my code?
EDIT:
Thanks all. It's pretty clear now.
You need to define template<typename T> std::string Derived<T>::Foo() { ... } and template<typename T>
std::string Derived<T>::Bar() { ... } in the header file. When the compiler is compiling test.cpp it doesn't know all the possible values of T that you might use in other parts of the program.
I think there are some compilers that have connections between the compiling and linking steps that notice references to missing template instantiations and go instantiate them from the .cpp file where they are declared. But I don't know which they are, and the functionality is exceedingly rare to find.
If you define them in the header file most compilers will emit them as a 'weak' symbol into every compilation unit in which they're referenced. And the linker will toss out all except for one definition of the weak symbol. This causes extra compilation time.
Alternately, there are syntaxes for explicitly instantiating templates and forcing the compiler to emit definitions right there. But that requires you to be aware of all the values T could possibly have and you will inevitably miss some.
You have to ensure that the member functions are instantiate for all the required types somewhere.
Usually this is accomplished by defining template functions inline in the header file where they are declared so that any use of the functions will cause them to be instantiated.
As an alternative, you can use explicit instantiations in the source file where you define them but this does require you to know in advance all the types that your template will ever be instantiated for.
This doesn't really have much to do with derivation. It's just a general rule with templates: with most compilers (anything but Comeau) you have to put the full implementation of a template where it's visible in every translation unit that will instantiate that template -- normally in the header.
Even with Comeau, you have to use the export keyword to make things work right. Since They're the only ones that implement export, chances are pretty good that you don't care much though.