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 ?
Related
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.
I am using static template members in a class; the templates are instantiated in a cpp built in a software. I have a plug-in for the software that uses the name() template method in the header, but does not build the source file which contains the instantiation. The build works on Linux with g++-4.9 but fails on MinGW 4.8. I want to know how to make it work with the almost same compiler, but on Windows instead.
.hpp :
enum class ToplevelMenuElement
{
FileMenu,
...
AboutMenu
};
enum class FileMenuElement
{
New,
... ,
Quit
};
// Others menus macros are defined
class MenuInterface
{
public:
template<typename MenuType>
static QString name(MenuType elt);
private:
static const std::map<ToplevelMenuElement, QString> m_map;
static const std::map<FileMenuElement, QString> m_fileMap;
};
.cpp :
template<>
QString MenuInterface::name(ToplevelMenuElement elt)
{
return m_map.at(elt);
}
template<>
QString MenuInterface::name(FileMenuElement elt)
{
return m_fileMap.at(elt);
}
const std::map<ToplevelMenuElement, QString> MenuInterface::m_map
{
{ToplevelMenuElement::FileMenu, QObject::tr("File")},
...
{ToplevelMenuElement::AboutMenu, QObject::tr("About")}
};
const std::map<FileMenuElement, QString> MenuInterface::m_fileMap
{
{FileMenuElement::New, QObject::tr("New")},
...,
{FileMenuElement::Quit, QObject::tr("Quit")}
};
Error :
undefined reference to `QString MenuInterface::name<ToplevelMenuElement>(ToplevelMenuElement)'
Is there any flag to use to make some kind of lazy instantiation ? Or should I build the .cpp containing the template instantiation in my plug-in ?
Because you are linking a source file that contains explicit specializations, you need to declare your explicit specializations before you define them. From §14.7.3/3:
A declaration of a function template, class template, or variable template being explicitly specialized shall precede the declaration of the explicit specialization. [ Note: A declaration, but not a definition of the template is required. — end note ]
So you need to put these after your class in your header file:
template<>
QString MenuInterface::name(ToplevelMenuElement elt);
template<>
QString MenuInterface::name(FileMenuElement elt);
This has been asked many times...declaration and definitions for templates should be same file.
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)
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();
};
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.