Within a DLL I have an exported non-template class with a template base class. This template base class has a static member variable. I use the static base member in an executable that links to the DLL with the exported non-template class.
In many scenarios I get unresolved external symbols or complaints about inconsistent linkage. I have found one scenario that works, but it seems to be kludgey so I'm wondering if there is a better way and if that better way might also point to deficiencies in VS2010 SP1's C++ compiler/linker.
This is the minimal scenario of the DLL that I could distill - I don't think I could remove anything here without breaking the scenario.
// Header file
template<typename T>
class _MYDLL_EXPORTS TBaseClass
{
public:
static const double g_initial_value;
};
class _MYDLL_EXPORTS MyClass : public TBaseClass<MyClass>
{
};
// Kludge: use this code only when building the DLL, not when including
// from the DLL's client
#ifdef _MYDLL
template<typename T>
const double TBaseClass<T>::g_initial_value = 1e-5;
#endif
// CPP file
#include "header.h"
// Explicit instantiation of the template for the correct parameter.
template class TBaseClass<MyClass>;
Then the user of the DLL
#include <header.h>
#include <iostream>
int main(void) {
MyClass c;
std::cout << c.g_initial_value;
return 0;
}
In C++ generally, when a plain class has a static member, it should be declared in the header, but instantiated in a source file. To do otherwise would cause too many instances of the static class member to be created.
Templates are kind of the same way, except the compiler has some magic for templates that it doesn't have for non-templates. Specifically, it magically eliminates duplicate instances of a template instantiation during the linking phase of a build.
This is the source of your problem: The stuff inside the _MYDLL portion is automatically instantiated by every source file that includes this template and also makes TBaseClass objects. Then the linker automatically eliminates duplicates.
Trouble is, you have two links: the DLL link and the client link. Both will make TBaseClass instantiations, and both will make those g_initial_value objects.
To solve this: Move the stuff in the _MYDLL conditional into the CPP file, so the client won't get instructions to build the instance itself.
The fact that you are using your template class from both the DLL and the EXE make things more confusing, but still, it can work.
First of all, you should implement your template base class entirely in the header file. If you don't know why, then make sure you read the accepted answer to this question.
Now let's forget about templates and DLLs, and consider a much simpler case. Let's say you have class C, with a static member. You would normally code this class in this way:
// C.h file
class C {
public:
static const double g_initial_value;
};
// C.cpp file
const double C::g_initial_value = 1e-5;
Nothing odd or complicated here. Now consider what would happen if you move the static declaration to the header file. If there is only one source file that includes the header, then everything will work just fine. But if two or more source files included this header, then this static member will be defined multiple times, and the linker will not like that.
The same concept applies to a template class. Your #ifdef _MYDLL hack only works because from the DLL you are including this header file only once. But the moment you include this file from another source file you'll start getting linker errors on the DLL! So I completely agree with you, this is not a good solution.
I think one thing that complicates your setup is that you allow both the DLL and the EXE to instantiate this template base class. I think you would have a much cleaner solution if you find an "owner" for each instantiation of the template class. Following your code example, let's replace MyClass with MyDLLClass and MyEXEClass. Then you could make this work like this:
// dll.h
template<typename T>
class _MYDLL_EXPORTS TBaseClass
{
public:
static const double g_initial_value;
};
class _MYDLL_EXPORTS MyDLLClass : public TBaseClass<MyDLLClass>
{
};
// dll.cpp
#include "dll.h"
// this file "owns" MyDLLClass so the static is defined here
template<> const double TBaseClass<MyDLLClass>::g_initial_value = 1e-5;
// exe.h
#include "dll.h"
class MyEXEClass : public TBaseClass<MyEXEClass>
{
};
// exe.cpp
#include "exe.h"
#include <iostream>
// this file "owns" MyEXEClass so the static is defined here
template<> const double TBaseClass<MyEXEClass>::g_initial_value = 1e-5;
int main(int argc, char* argv[])
{
MyDLLClass dll;
MyEXEClass exe;
std::cout << dll.g_initial_value;
std::cout << exe.g_initial_value;
}
I hope this makes sense.
In fact, the exported class's base class is exported too if the base class is a template class, but not true on the contrary. Please refer to http://www.codesynthesis.com/~boris/blog/2010/01/18/dll-export-cxx-templates/
For your specific question, I suggest you define a static method in the base template which returns a variable(pointer?) of interest. Then only one definition will happen across multiple dlls or exe which depends on your library.
While I would suggest using your current approach, actually it's possible to avoid #ifdef by using older syntax for exporting templates from a DLL. All this goes to the DLL's header file:
#pragma once
#ifdef _MYDLL
#define _MYDLL_EXPORTS __declspec(dllexport)
#else
#define _MYDLL_EXPORTS __declspec(dllimport)
#endif
template<typename T>
class _MYDLL_EXPORTS TBaseClass // _MYDLL_EXPORTS is not needed here
{
public:
static double g_initial_value;
};
template<typename T>
double TBaseClass<T>::g_initial_value = 1e-5;
class MyClass;
template class _MYDLL_EXPORTS TBaseClass<MyClass>;
class _MYDLL_EXPORTS MyClass : public TBaseClass<MyClass>
{
};
At runtime the address of g_initial_value in the client code lies within DLL's address space so it seems to work correctly.
Related
I have some template code that I would prefer to have stored in a CPP file instead of inline in the header. I know this can be done as long as you know which template types will be used. For example:
.h file
class foo
{
public:
template <typename T>
void do(const T& t);
};
.cpp file
template <typename T>
void foo::do(const T& t)
{
// Do something with t
}
template void foo::do<int>(const int&);
template void foo::do<std::string>(const std::string&);
Note the last two lines - the foo::do template function is only used with ints and std::strings, so those definitions mean the app will link.
My question is - is this a nasty hack or will this work with other compilers/linkers? I am only using this code with VS2008 at the moment but will be wanting to port to other environments.
The problem you describe can be solved by defining the template in the header, or via the approach you describe above.
I recommend reading the following points from the C++ FAQ Lite:
Why can’t I separate the definition of my templates class from its declaration and put it inside a .cpp file?
How can I avoid linker errors with my template functions?
How does the C++ keyword export help with template linker errors?
They go into a lot of detail about these (and other) template issues.
For others on this page wondering what the correct syntax is (as did I) for explicit template specialisation (or at least in VS2008), its the following...
In your .h file...
template<typename T>
class foo
{
public:
void bar(const T &t);
};
And in your .cpp file
template <class T>
void foo<T>::bar(const T &t)
{ }
// Explicit template instantiation
template class foo<int>;
Your example is correct but not very portable.
There is also a slightly cleaner syntax that can be used (as pointed out by #namespace-sid, among others).
However, suppose the templated class is part of some library that is to be shared...
Should other versions of the templated class be compiled?
Is the library maintainer supposed to anticipate all possible templated uses of the class?
An Alternate Approach
Add a third file that is the template implementation/instantiation file in your sources.
lib/foo.hpp - from library
#pragma once
template <typename T>
class foo {
public:
void bar(const T&);
};
lib/foo.cpp - compiling this file directly just wastes compilation time
// Include guard here, just in case
#pragma once
#include "foo.hpp"
template <typename T>
void foo::bar(const T& arg) {
// Do something with `arg`
}
foo.MyType.cpp - using the library, explicit template instantiation of foo<MyType>
// Consider adding "anti-guard" to make sure it's not included in other translation units
#if __INCLUDE_LEVEL__
#error "Don't include this file"
#endif
// Yes, we include the .cpp file
#include <lib/foo.cpp>
#include "MyType.hpp"
template class foo<MyType>;
Organize your implementations as desired:
All implementations in one file
Multiple implementation files, one for each type
An implementation file for each set of types
Why??
This setup should reduce compile times, especially for heavily used complicated templated code, because you're not recompiling the same header file in each
translation unit.
It also enables better detection of which code needs to be recompiled, by compilers and build scripts, reducing incremental build burden.
Usage Examples
foo.MyType.hpp - needs to know about foo<MyType>'s public interface but not .cpp sources
#pragma once
#include <lib/foo.hpp>
#include "MyType.hpp"
// Declare `temp`. Doesn't need to include `foo.cpp`
extern foo<MyType> temp;
examples.cpp - can reference local declaration but also doesn't recompile foo<MyType>
#include "foo.MyType.hpp"
MyType instance;
// Define `temp`. Doesn't need to include `foo.cpp`
foo<MyType> temp;
void example_1() {
// Use `temp`
temp.bar(instance);
}
void example_2() {
// Function local instance
foo<MyType> temp2;
// Use templated library function
temp2.bar(instance);
}
error.cpp - example that would work with pure header templates but doesn't here
#include <lib/foo.hpp>
// Causes compilation errors at link time since we never had the explicit instantiation:
// template class foo<int>;
// GCC linker gives an error: "undefined reference to `foo<int>::bar()'"
foo<int> nonExplicitlyInstantiatedTemplate;
void linkerError() {
nonExplicitlyInstantiatedTemplate.bar();
}
Note: Most compilers/linters/code helpers won't detect this as an error, since there is no error according to C++ standard.
But when you go to link this translation unit into a complete executable, the linker won't find a defined version of foo<int>.
Alternate approach from: https://stackoverflow.com/a/495056/4612476
This code is well-formed. You only have to pay attention that the definition of the template is visible at the point of instantiation. To quote the standard, § 14.7.2.4:
The definition of a non-exported function template, a non-exported member function template, or a non-exported member function or static data member of a class template shall be present in every translation unit in which it is explicitly instantiated.
This should work fine everywhere templates are supported. Explicit template instantiation is part of the C++ standard.
That is a standard way to define template functions. I think there are three methods I read for defining templates. Or probably 4. Each with pros and cons.
Define in class definition. I don't like this at all because I think class definitions are strictly for reference and should be easy to read. However it is much less tricky to define templates in class than outside. And not all template declarations are on the same level of complexity. This method also makes the template a true template.
Define the template in the same header, but outside of the class. This is my preferred way most of the times. It keeps your class definition tidy, the template remains a true template. It however requires full template naming which can be tricky. Also, your code is available to all. But if you need your code to be inline this is the only way. You can also accomplish this by creating a .INL file at the end of your class definitions.
Include the header.h and implementation.CPP into your main.CPP. I think that's how its done. You won't have to prepare any pre instantiations, it will behave like a true template. The problem I have with it is that it is not natural. We don't normally include and expect to include source files. I guess since you included the source file, the template functions can be inlined.
This last method, which was the posted way, is defining the templates in a source file, just like number 3; but instead of including the source file, we pre instantiate the templates to ones we will need. I have no problem with this method and it comes in handy sometimes. We have one big code, it cannot benefit from being inlined so just put it in a CPP file. And if we know common instantiations and we can predefine them. This saves us from writing basically the same thing 5, 10 times. This method has the benefit of keeping our code proprietary. But I don't recommend putting tiny, regularly used functions in CPP files. As this will reduce the performance of your library.
Note, I am not aware of the consequences of a bloated obj file.
Let's take one example, let's say for some reason you want to have a template class:
//test_template.h:
#pragma once
#include <cstdio>
template <class T>
class DemoT
{
public:
void test()
{
printf("ok\n");
}
};
template <>
void DemoT<int>::test()
{
printf("int test (int)\n");
}
template <>
void DemoT<bool>::test()
{
printf("int test (bool)\n");
}
If you compile this code with Visual Studio - it works out of box.
gcc will produce linker error (if same header file is used from multiple .cpp files):
error : multiple definition of `DemoT<int>::test()'; your.o: .../test_template.h:16: first defined here
It's possible to move implementation to .cpp file, but then you need to declare class like this -
//test_template.h:
#pragma once
#include <cstdio>
template <class T>
class DemoT
{
public:
void test()
{
printf("ok\n");
}
};
template <>
void DemoT<int>::test();
template <>
void DemoT<bool>::test();
// Instantiate parametrized template classes, implementation resides on .cpp side.
template class DemoT<bool>;
template class DemoT<int>;
And then .cpp will look like this:
//test_template.cpp:
#include "test_template.h"
template <>
void DemoT<int>::test()
{
printf("int test (int)\n");
}
template <>
void DemoT<bool>::test()
{
printf("int test (bool)\n");
}
Without two last lines in header file - gcc will work fine, but Visual studio will produce an error:
error LNK2019: unresolved external symbol "public: void __cdecl DemoT<int>::test(void)" (?test#?$DemoT#H##QEAAXXZ) referenced in function
template class syntax is optional in case if you want to expose function via .dll export, but this is applicable only for windows platform - so test_template.h could look like this:
//test_template.h:
#pragma once
#include <cstdio>
template <class T>
class DemoT
{
public:
void test()
{
printf("ok\n");
}
};
#ifdef _WIN32
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT
#endif
template <>
void DLL_EXPORT DemoT<int>::test();
template <>
void DLL_EXPORT DemoT<bool>::test();
with .cpp file from previous example.
This however gives more headache to linker, so it's recommended to use previous example if you don't export .dll function.
This is definitely not a nasty hack, but be aware of the fact that you will have to do it (the explicit template specialization) for every class/type you want to use with the given template. In case of MANY types requesting template instantiation there can be A LOT of lines in your .cpp file. To remedy this problem you can have a TemplateClassInst.cpp in every project you use so that you have greater control what types will be instantiated. Obviously this solution will not be perfect (aka silver bullet) as you might end up breaking the ODR :).
There is, in the latest standard, a keyword (export) that would help alleviate this issue, but it isn't implemented in any compiler that I'm aware of, other than Comeau.
See the FAQ-lite about this.
Yes, that's the standard way to do specializiation explicit instantiation. As you stated, you cannot instantiate this template with other types.
Edit: corrected based on comment.
None of above worked for me, so here is how y solved it, my class have only 1 method templated..
.h
class Model
{
template <class T>
void build(T* b, uint32_t number);
};
.cpp
#include "Model.h"
template <class T>
void Model::build(T* b, uint32_t number)
{
//implementation
}
void TemporaryFunction()
{
Model m;
m.build<B1>(new B1(),1);
m.build<B2>(new B2(), 1);
m.build<B3>(new B3(), 1);
}
this avoid linker errors, and no need to call TemporaryFunction at all
Time for an update! Create an inline (.inl, or probably any other) file and simply copy all your definitions in it. Be sure to add the template above each function (template <typename T, ...>). Now instead of including the header file in the inline file you do the opposite. Include the inline file after the declaration of your class (#include "file.inl").
I don't really know why no one has mentioned this. I see no immediate drawbacks.
There is nothing wrong with the example you have given. But i must say i believe it's not efficient to store function definitions in a cpp file. I only understand the need to separate the function's declaration and definition.
When used together with explicit class instantiation, the Boost Concept Check Library (BCCL) can help you generate template function code in cpp files.
I do not have access to c++11 for this project.
I have a C++ class; lets call it Bar, it looks something like this:
Header FooBar.h:
#include "Fancy.h" // <--- Dependency
namespace Foo
{
template<typename T>
class Bar : public Fancy::FancyClass<T, ALLOCATER<HARD_CODED_VALUE>>
{
};
}
Cpp:
None
Fancy is a lib that is being statically linked into a dll. The problem is that when other projects want to use the dll they include "FooBar.h" it says that it cannot find "Fancy.h"
Basically I want projects that include the dll to be able to use this class without needing any additional libraries or headers.
My solution was to just put it in a cpp and have no header file. Unfortintly nothing can find it then? I have tried creating a blank header file that did not work either.
I tried to forward declare it in the header but to do that I need the .h to understand what FancyClass is. I have also tried
namespace Fancy
{
class FancyClass;
class ALLOCATER;
}
namespace Foo
{
template<typename T>
class Bar : public Fancy::FancyClass<T, ALLOCATER<HARD_CODED_VALUE>>;
}
in the header. But that causes many errors.
Short answer, you must include the header in your executable file in order to use the provided library.
Long(er) answer, the compiler needs to know the structure of the class defined in the library.
Imagine that there is a class called MyAwesomeClass that is part of a library you want to use in your executable. The compiler doesn't know anything about that class when you say MyAwesomeClass awesome;. How big is it? What methods can you call on it? Does it inherit from anything?
This information is contained in the header file where the class is declared.
class MyAwesomeClass
{
private:
std::string _name;
public:
MyAwesomeClass();
MyAwesomeClass(const std::string& name);
void print_name();
};
The implementation is defined in the DLL or static library, but when using the type MyAwesomeClass, the compiler needs to know at least its structure. Without including the header, the compiler will complain that it doesn't know what type MyAwesomeClass is (ie. undefined class errors).
I'm building an header-only library, and I've resolved some circular dependency issues by doing something similar to what the code shows.
Basically, I create a private template implementation that allows me to use forward-declared types as if they were included and not forward-declared.
Is there anything dangerous about my approach?
Is there any performance loss? (the library's main focus is performance - the real code has explicit inline suggestions)
Bonus question: is there an impact (positive or negative) on compilation time?
// Entity.h
#include "Component.h"
struct Entity { void a() { ... } }
// Component.h
struct Entity; // forward-declaration
class Component
{
Entity& entity;
template<class T = Entity> void doAImpl() { static_cast<T&>(entity).a(); }
public:
// void notWorking() { entity.a(); } <- this does not compile
void doA() { doAImpl(); }
}
Is there anything dangerous about my approach?
As long as the template instantiation is, in fact, deferred, not much can go wrong. It could maybe declare intent a bit better if you prohibited an incorrect instantiation:
typename std::enable_if< std::is_same< T, Entity >::value
&& sizeof ( T ) /* Ensure that Entity is not incomplete. */ >::type
On second reading of your code, it looks like the non-template doA function will immediately and prematurely instantiate doAImpl, defeating the templating. I don't think the public interface can be a non-template, since it must cause instantiation of whatever Impl ultimately does the work, but only when the function is actually used. Unless there's another layer of templating protecting the user, it's probably better to do away with the private part and do everything in doA.
Is there any performance loss?
Nope. The function is sure to be inlined either way.
Is there an impact (positive or negative) on compilation time?
The minuscule added complexity will certainly not make a difference.
The only reason not to do this is obvious: it's ugly. And quite likely a violation of separation of concerns.
One workaround would be to use a non-member, free function instead.
struct Entity;
void a( Entity & );
void doA() { a( entity ); }
Another would be to simply treat Entity.h or whatever as a dependency and include it. I think this would be the most popular solution.
If Component is really not dependent on Entity, then maybe doA belongs in a derived class which should have its own new header, which includes both the existing ones.
The code in the header Component.h will fail to compile unless you also #include Entity.h. This will result in mysterious errors in Component.h if you were ever to try to #include Component.h separately; to change Entity.h so that it does not contain a complete definition of Entity; or to change Library.h so that it no longer contains #include Entity.h. This is generally considered bad practice as this error would be difficult to understand for a future maintainer of the code.
clang gives error: member access into incomplete type 'Entity'
Here's a live example demonstrating the error: http://coliru.stacked-crooked.com/view?id=d6737c6f710992cce8a3f28217562da2-25dabfc2c190f5ef027f31d968947336
The function doAImpl() is instantiated if it is called in a context that does not depend on a template parameter. At the point of instantiation, Entity is used in a class-member-access and therefore required to be complete. If you do not #include Entity.h, the type Entity will not be complete at the point of instantiation.
A much simpler (and prettier) way to achieve what you want is to do:
template<class Entity>
class Component
{
Entity& entity;
public:
void doA() { entity.a(); } // this compiles fine
};
In general, (even in a header-only library) you can avoid a lot of headaches by following this simple rule: every header name.h must have a matching name.cpp which contains #include name.h before any other #include directive. This guarantees that name.h can be safely included anywhere without resulting in this kind of error.
This is the canonical reference, from John Lakos in Large-Scale C++ Software Design, quoted by Bruce Eckel in Thinking in C++: http://bruce-eckel.developpez.com/livres/cpp/ticpp/v1/?page=page_18
Latent usage errors can be avoided by ensuring that the .h file of a component parses by itself - without externally-provided declarations or definitions... Including the .h file as the very first line of the .c file ensures that no critical piece of information intrinsic to the physical interface of the component is missing from the .h file (or, if there is, that you will find out about it as soon as you try to compile the .c file).
I would suggest to put implementation in "*.inl"
// Entity.h
#ifndef ENTITY_H
#define ENTITY_H
class Component; // forward-declaration
struct Entity { void a(); };
#include "Entity.inl"
#endif
// Entity.inl
#ifndef ENTITY_INL
#define ENTITY_INL
#include "Component.h";
inline void Entity::a() { /* implementation using Component and Entity */}
#endif
// Component.h
#ifndef COMPONENT_H
#define COMPONENT_H
struct Entity; // forward-declaration
class Component
{
Entity& entity;
public:
void doA();
};
#include "Component.inl"
#endif
// Component.inl
#ifndef COMPONENT_INL
#define COMPONENT_INL
#include "Entity.h";
inline void Component::doA() { entity.a(); }
#endif
It was sufficient to declare doA in Component.h, and define it in Entity.h.
// Component.h
class Entity;
class Component
{
void doA();
}
// Entity.h
class Entity { ... }
// still in Entity.h
void Component::doA() { entity.a(); }
I'm trying to create a C++ class, with a templated superclass. The idea being, I can easily create lots of similar subclasses from a number of superclasses which have similar characteristics.
I have distilled the problematic code as follows:
template_test.h:
template<class BaseClass>
class Templated : public BaseClass
{
public:
Templated(int a);
virtual int Foo();
};
class Base
{
protected:
Base(int a);
public:
virtual int Foo() = 0;
protected:
int b;
};
template_test.cpp:
#include "template_test.h"
Base::Base(int a)
: b(a+1)
{
}
template<class BaseClass>
Templated<BaseClass>::Templated(int a)
: BaseClass(a)
{
}
template<class BaseClass>
int Templated<BaseClass>::Foo()
{
return this->b;
}
main.cpp:
#include "template_test.h"
int main()
{
Templated<Base> test(1);
return test.Foo();
}
When I build the code, I get linker errors, saying that the symbols Templated<Base>::Templated(int) and Templated<Base>::Foo() cannot be found.
A quick Google suggests that adding the following to main.cpp will solve the problem:
template<> Templated<Base>::Templated(int a);
template<> int Templated<Base>::Foo();
But this does not solve the problem. Adding the lines to main.cpp does not work either. (Though, interestingly, adding them to both gives 'multiply defined symbol' errors from the linker, so they must be doing something...)
However, putting all the code in one source file does solve the problem. While this would be ok for the noddy example above, the real application I'm looking at would become unmanageable very fast if I was forced to put the whole lot in one cpp file.
Does anyone know if what I'm doing is even possible? (How) can I solve my linker errors?
I would assume that I could make all the methods in class Templated inline and this would work, but this doesn't seem ideal either.
With templated classes, the definitions must be available for each translation unit that uses it. The definitions can go in a separate file, usually with .inl or .tcc extension; the header file #includes that file at the bottom. Thus, even though it's in a separate file, it's still #included for each translation unit; it cannot be standalone.
So, for your example, rename template_test.cpp to template_test.inl (or template_test.tcc, or whatever), then have #include "template_test.inl" (or whatever) at the bottom of template_test.h, just before the #endif of the include guard.
Hope this helps!
The problem is that when your Templated file is compiled, the compiler doesn't know what types it will need to generate code for, so it doesn't.
Then when you link, main.cpp says it needs those functions, but they were never compiled into object files, so the linker can't find them.
The other answers show ways to solve this problem in a portable way, in essence putting the definitions of the templated member functions in a place that is visible from where you instantiate instances of that class -- either through explicit instantiation, or putting the implementations in a file that is #included from main.cpp.
You may also want to read your compiler's documentation to see how they recommends setting things up. I know the IBM XLC compiler has some different settings and options for how to set these up.
The C++ FAQ-lite covers this, and a couple of ways round it.
You don't have to make all the methods "inline", but you should define the method bodies in template_test.h, rather in template_test.cpp.
Some compilers can handle this split, but you have to remember that at one level, templates are like macros. for the compiler to generate the a template for your particular , it needs to have the template source handy.
When the compiler is compiling main.cpp, it sees the class definition has member function declarations, but no member function defintions. It just assumes that there must be a definition of "Templated" constructor and Foo implementation somewhere, so it defers to the linker to find it at link time.
The solution to your problem is to put the implementation of Templated into template.h.
eg
template<class BaseClass>
class Templated : public BaseClass
{
public:
Templated(int a) : BaseClass(a) {}
virtual int Foo() { return BaseClass::b; }
};
Interestingly, I could get your code to link by putting this at the end of template_test.cpp.
void Nobody_Ever_Calls_This()
{
Templated<Base> dummy(1);
}
Now the compiler can find an instance of Templated to link with. I wouldn't recommend this as a technique. Some other file might want to create a
Templated<Widget>
and then you'd have to add another explicit instantiation to template_test.cpp.
I have some template code that I would prefer to have stored in a CPP file instead of inline in the header. I know this can be done as long as you know which template types will be used. For example:
.h file
class foo
{
public:
template <typename T>
void do(const T& t);
};
.cpp file
template <typename T>
void foo::do(const T& t)
{
// Do something with t
}
template void foo::do<int>(const int&);
template void foo::do<std::string>(const std::string&);
Note the last two lines - the foo::do template function is only used with ints and std::strings, so those definitions mean the app will link.
My question is - is this a nasty hack or will this work with other compilers/linkers? I am only using this code with VS2008 at the moment but will be wanting to port to other environments.
The problem you describe can be solved by defining the template in the header, or via the approach you describe above.
I recommend reading the following points from the C++ FAQ Lite:
Why can’t I separate the definition of my templates class from its declaration and put it inside a .cpp file?
How can I avoid linker errors with my template functions?
How does the C++ keyword export help with template linker errors?
They go into a lot of detail about these (and other) template issues.
For others on this page wondering what the correct syntax is (as did I) for explicit template specialisation (or at least in VS2008), its the following...
In your .h file...
template<typename T>
class foo
{
public:
void bar(const T &t);
};
And in your .cpp file
template <class T>
void foo<T>::bar(const T &t)
{ }
// Explicit template instantiation
template class foo<int>;
Your example is correct but not very portable.
There is also a slightly cleaner syntax that can be used (as pointed out by #namespace-sid, among others).
However, suppose the templated class is part of some library that is to be shared...
Should other versions of the templated class be compiled?
Is the library maintainer supposed to anticipate all possible templated uses of the class?
An Alternate Approach
Add a third file that is the template implementation/instantiation file in your sources.
lib/foo.hpp - from library
#pragma once
template <typename T>
class foo {
public:
void bar(const T&);
};
lib/foo.cpp - compiling this file directly just wastes compilation time
// Include guard here, just in case
#pragma once
#include "foo.hpp"
template <typename T>
void foo::bar(const T& arg) {
// Do something with `arg`
}
foo.MyType.cpp - using the library, explicit template instantiation of foo<MyType>
// Consider adding "anti-guard" to make sure it's not included in other translation units
#if __INCLUDE_LEVEL__
#error "Don't include this file"
#endif
// Yes, we include the .cpp file
#include <lib/foo.cpp>
#include "MyType.hpp"
template class foo<MyType>;
Organize your implementations as desired:
All implementations in one file
Multiple implementation files, one for each type
An implementation file for each set of types
Why??
This setup should reduce compile times, especially for heavily used complicated templated code, because you're not recompiling the same header file in each
translation unit.
It also enables better detection of which code needs to be recompiled, by compilers and build scripts, reducing incremental build burden.
Usage Examples
foo.MyType.hpp - needs to know about foo<MyType>'s public interface but not .cpp sources
#pragma once
#include <lib/foo.hpp>
#include "MyType.hpp"
// Declare `temp`. Doesn't need to include `foo.cpp`
extern foo<MyType> temp;
examples.cpp - can reference local declaration but also doesn't recompile foo<MyType>
#include "foo.MyType.hpp"
MyType instance;
// Define `temp`. Doesn't need to include `foo.cpp`
foo<MyType> temp;
void example_1() {
// Use `temp`
temp.bar(instance);
}
void example_2() {
// Function local instance
foo<MyType> temp2;
// Use templated library function
temp2.bar(instance);
}
error.cpp - example that would work with pure header templates but doesn't here
#include <lib/foo.hpp>
// Causes compilation errors at link time since we never had the explicit instantiation:
// template class foo<int>;
// GCC linker gives an error: "undefined reference to `foo<int>::bar()'"
foo<int> nonExplicitlyInstantiatedTemplate;
void linkerError() {
nonExplicitlyInstantiatedTemplate.bar();
}
Note: Most compilers/linters/code helpers won't detect this as an error, since there is no error according to C++ standard.
But when you go to link this translation unit into a complete executable, the linker won't find a defined version of foo<int>.
Alternate approach from: https://stackoverflow.com/a/495056/4612476
This code is well-formed. You only have to pay attention that the definition of the template is visible at the point of instantiation. To quote the standard, § 14.7.2.4:
The definition of a non-exported function template, a non-exported member function template, or a non-exported member function or static data member of a class template shall be present in every translation unit in which it is explicitly instantiated.
This should work fine everywhere templates are supported. Explicit template instantiation is part of the C++ standard.
That is a standard way to define template functions. I think there are three methods I read for defining templates. Or probably 4. Each with pros and cons.
Define in class definition. I don't like this at all because I think class definitions are strictly for reference and should be easy to read. However it is much less tricky to define templates in class than outside. And not all template declarations are on the same level of complexity. This method also makes the template a true template.
Define the template in the same header, but outside of the class. This is my preferred way most of the times. It keeps your class definition tidy, the template remains a true template. It however requires full template naming which can be tricky. Also, your code is available to all. But if you need your code to be inline this is the only way. You can also accomplish this by creating a .INL file at the end of your class definitions.
Include the header.h and implementation.CPP into your main.CPP. I think that's how its done. You won't have to prepare any pre instantiations, it will behave like a true template. The problem I have with it is that it is not natural. We don't normally include and expect to include source files. I guess since you included the source file, the template functions can be inlined.
This last method, which was the posted way, is defining the templates in a source file, just like number 3; but instead of including the source file, we pre instantiate the templates to ones we will need. I have no problem with this method and it comes in handy sometimes. We have one big code, it cannot benefit from being inlined so just put it in a CPP file. And if we know common instantiations and we can predefine them. This saves us from writing basically the same thing 5, 10 times. This method has the benefit of keeping our code proprietary. But I don't recommend putting tiny, regularly used functions in CPP files. As this will reduce the performance of your library.
Note, I am not aware of the consequences of a bloated obj file.
Let's take one example, let's say for some reason you want to have a template class:
//test_template.h:
#pragma once
#include <cstdio>
template <class T>
class DemoT
{
public:
void test()
{
printf("ok\n");
}
};
template <>
void DemoT<int>::test()
{
printf("int test (int)\n");
}
template <>
void DemoT<bool>::test()
{
printf("int test (bool)\n");
}
If you compile this code with Visual Studio - it works out of box.
gcc will produce linker error (if same header file is used from multiple .cpp files):
error : multiple definition of `DemoT<int>::test()'; your.o: .../test_template.h:16: first defined here
It's possible to move implementation to .cpp file, but then you need to declare class like this -
//test_template.h:
#pragma once
#include <cstdio>
template <class T>
class DemoT
{
public:
void test()
{
printf("ok\n");
}
};
template <>
void DemoT<int>::test();
template <>
void DemoT<bool>::test();
// Instantiate parametrized template classes, implementation resides on .cpp side.
template class DemoT<bool>;
template class DemoT<int>;
And then .cpp will look like this:
//test_template.cpp:
#include "test_template.h"
template <>
void DemoT<int>::test()
{
printf("int test (int)\n");
}
template <>
void DemoT<bool>::test()
{
printf("int test (bool)\n");
}
Without two last lines in header file - gcc will work fine, but Visual studio will produce an error:
error LNK2019: unresolved external symbol "public: void __cdecl DemoT<int>::test(void)" (?test#?$DemoT#H##QEAAXXZ) referenced in function
template class syntax is optional in case if you want to expose function via .dll export, but this is applicable only for windows platform - so test_template.h could look like this:
//test_template.h:
#pragma once
#include <cstdio>
template <class T>
class DemoT
{
public:
void test()
{
printf("ok\n");
}
};
#ifdef _WIN32
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT
#endif
template <>
void DLL_EXPORT DemoT<int>::test();
template <>
void DLL_EXPORT DemoT<bool>::test();
with .cpp file from previous example.
This however gives more headache to linker, so it's recommended to use previous example if you don't export .dll function.
This is definitely not a nasty hack, but be aware of the fact that you will have to do it (the explicit template specialization) for every class/type you want to use with the given template. In case of MANY types requesting template instantiation there can be A LOT of lines in your .cpp file. To remedy this problem you can have a TemplateClassInst.cpp in every project you use so that you have greater control what types will be instantiated. Obviously this solution will not be perfect (aka silver bullet) as you might end up breaking the ODR :).
There is, in the latest standard, a keyword (export) that would help alleviate this issue, but it isn't implemented in any compiler that I'm aware of, other than Comeau.
See the FAQ-lite about this.
Yes, that's the standard way to do specializiation explicit instantiation. As you stated, you cannot instantiate this template with other types.
Edit: corrected based on comment.
None of above worked for me, so here is how y solved it, my class have only 1 method templated..
.h
class Model
{
template <class T>
void build(T* b, uint32_t number);
};
.cpp
#include "Model.h"
template <class T>
void Model::build(T* b, uint32_t number)
{
//implementation
}
void TemporaryFunction()
{
Model m;
m.build<B1>(new B1(),1);
m.build<B2>(new B2(), 1);
m.build<B3>(new B3(), 1);
}
this avoid linker errors, and no need to call TemporaryFunction at all
Time for an update! Create an inline (.inl, or probably any other) file and simply copy all your definitions in it. Be sure to add the template above each function (template <typename T, ...>). Now instead of including the header file in the inline file you do the opposite. Include the inline file after the declaration of your class (#include "file.inl").
I don't really know why no one has mentioned this. I see no immediate drawbacks.
There is nothing wrong with the example you have given. But i must say i believe it's not efficient to store function definitions in a cpp file. I only understand the need to separate the function's declaration and definition.
When used together with explicit class instantiation, the Boost Concept Check Library (BCCL) can help you generate template function code in cpp files.