Use of templates in external libraries

It appears there is a gap in my understanding of templates in C++. I have a recent post where the use of my own template in an external dll caused linking errors when importing into another library. Example:

from the "core" library (dynamically linked)
1
2
3
4
5
template <typename T>
class API_EXPORT MyTemplateClass
{
	//...whatever methods are defined here.  INCLUDES INLINES
};


from a separate library that uses and links to the "core" library
1
2
3
4
class MyImplementationClass : MyTemplateClass<SomeImportedClass>
{
	//...whatever methods are defined here.
};


The result of a compilation of the above would result in an inability to link to any method that should be generated by the template for MyTemplateClass<SomeImportedClass> whether it was inlined or explicitly defined.

From what I have read in some places on the internet, this kind of use of template classes cannot be done without knowing ahead of time the types that will be used with it. Doing so will result in the linking errors I am experiencing. So my questions:

1. Is this a misunderstanding? Can this be done?
2. If not, then why does the following code compile without any problems? (Vector is a template class). I am certain that writers did not explicitly instatiate a vector for "TestClass". I can do this with other libraries with templates as well.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#pragma once
#include <vector>
class TestClass
{
public:
	TestClass();
	~TestClass();

private:
	class GenericTest : public GenericClass<TestClass>
	{
		GenericTest(/*const TestClass& data*/);
	};

	static GenericTest _test;
	//virtual void PureTestVirtualFunction() = 0;
};

class TestVector : public std::vector<TestClass>
{
	// cpp includes code that instantiates the vector<TestClass>.
};


Last edited on
1. In the general case, which is when the template class know nothing about the template parameters that may be passed: no, it can't be done. Template classes "exported" from libraries must be wholly defined in their headers (or in files included by those headers).
2. The example is incomplete. What is GenericClass, and where is it defined?
It is simple: templated class cannot be linked and hence is not compiled [into the dll].
@helios

1. What do you mean by "wholly defined"?
2. Sorry. You are looking at the wrong example. Look at TestVector below it. TestVector is derived from std::vector

Here is another counterexample of what you are saying. This compiled and linked just fine and relies on "importing" both the QHash and QList templates from the Qt libraries:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#pragma once

#include "qthashtemplatetest_global.h"
#include <qhash.h>
#include <qlist.h>

class QTHASHTEMPLATETEST_EXPORT MyClass
{
private:
	int m;
	int n;

public:
	MyClass(int x, int y);
	~MyClass();

	inline bool operator ==(const MyClass& o) const { return (m == o.m) && (n == o.n); }
};

class QTHASHTEMPLATETEST_EXPORT QtHashTemplateTest : public QHash<int, MyClass*>
{
public:
	QtHashTemplateTest();
};

class QTHASHTEMPLATETEST_EXPORT QtTestListClass : public QList<MyClass*>
{
public:
	QtTestListClass();
};
Last edited on
What do you mean by "wholly defined"?

The entire class definition, including the definitions of the methods.

IOW, don't put the method definitions in a CPP file that gets linked against. Because the definitions have to be known by the compiler at compile-time.
Turning MyClass* into MyClass with the templates above also works if I add a default constructor to MyClass; though that would probably not be a good idea for this class. The point is it compiles and links just fine.
Last edited on
If you look inside qlist.h header you'll find that it contains the definition of the QList class template including definitions for all its member functions.
Last edited on
@MikeyBoy and Peter87

Yeah. So is mine. In fact, all of the functions are inlined or pure virtual; so there is no reason for them to be in a C++ file. Just like many of QList's functions:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename LibraryStringType>
class IIMOECORE_EXPORT NamedLibraryObject : public NamedObject
{
protected:
	LibraryStringType _name;

protected /*inline*/:
	inline NamedLibraryObject(const LibraryStringType& name, __uint32 referenceID) : NamedObject(referenceID), _name(name) { }
	inline ~NamedLibraryObject() { }
public /*inline*/:
	inline const LibraryStringType libraryFormattedName() const { return _name; }

public /*pure virtual*/:
	virtual void setName(const LibraryStringType& newName) = 0;
};
Last edited on
What are the errors you get?
As with the earlier examples, the template above is located in a separate library. I only have a single base class that uses the above template (so far) in the current library. These should all be produced by the template:

1
2
3
4
5
6
7
8
9
10
11
12
class SIMILEAPI_EXPORT IIMObject : public NamedLibraryObject<QByteArray>
{
public:
	inline IIMObject(const QByteArray& name, __uint32 referenceID) : NamedLibraryObject<QByteArray>(name, referenceID) { }
	static const __uint32 calculateHashValue(const __standardChar* name, __uint32 referenceID);
	~IIMObject();

public overrides:
	virtual const __standardChar* name() const override;
	virtual const __uint32 calculateHashValue() override;
	virtual void setName(const QByteArray& name) override;
};


Note that the extra overrides above are overrides for the NamedObject class that the template in my previous post inherits from.

I get multiple instances of the following 3 errors, one for each of the classes that inherit from IIMObject. I get one for the main constructor, one for for the copy constructor; and oddly, one for the assignment operator for the template class instance.

Severity Code Description Project File Line Suppression State
Error LNK2001 unresolved external symbol "__declspec(dllimport) protected: __thiscall IIMOEngine::NamedLibraryObject<class QByteArray>::NamedLibraryObject<class QByteArray>(class QByteArray const &,unsigned int)" (__imp_??0?$NamedLibraryObject@VQByteArray@@@IIMOEngine@@IAE@ABVQByteArray@@I@Z) SIMILEAPI D:\Developing\Projects\IIM\METAphor\SIMILEAPI\TestObject.obj 1

Severity Code Description Project File Line Suppression State
Error LNK2001 unresolved external symbol "__declspec(dllimport) public: __thiscall IIMOEngine::NamedLibraryObject<class QByteArray>::NamedLibraryObject<class QByteArray>(class IIMOEngine::NamedLibraryObject<class QByteArray> const &)" (__imp_??0?$NamedLibraryObject@VQByteArray@@@IIMOEngine@@QAE@ABV01@@Z) SIMILEAPI D:\Developing\Projects\IIM\METAphor\SIMILEAPI\TestObject.obj 1

Severity Code Description Project File Line Suppression State
Error LNK2001 unresolved external symbol "__declspec(dllimport) public: class IIMOEngine::NamedLibraryObject<class QByteArray> & __thiscall IIMOEngine::NamedLibraryObject<class QByteArray>::operator=(class IIMOEngine::NamedLibraryObject<class QByteArray> const &)" (__imp_??4?$NamedLibraryObject@VQByteArray@@@IIMOEngine@@QAEAAV01@ABV01@@Z) SIMILEAPI D:\Developing\Projects\IIM\METAphor\SIMILEAPI\TestObject.obj 1


Last edited on
I think the problem is that you declared NamedLibraryObject with export linkage, so when the linker tries to link the object that contains IIMObject, it will try to link to an imported NamedLibraryObject<QByteArray>, which doesn't exist (there should be a non-imported NamedLibraryObject<QByteArray>, but its member functions will have different symbols).

Remove the IIMOECORE_EXPORT from NamedLibraryObject, since it's impossible to export templates anyway.
Last edited on
LOL. THANK you helios. So the lesson to be learned is I should not export templates at all. Correct?
Correct. Template classes should all be in the header. As we've already established, there should be nothing to link against. So what is there to export?
Topic archived. No new replies allowed.