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.
Suppose I am attempting to create my own implementation of boost::filesystem::path, using the Curiously Recurring Template Pattern:
(Code is given incomplete for brevity, but will exhibit the problem as stated when compiled with 'g++ -std=c++11 -o mypath ./mypath.cpp', using GCC 4.8.4)
mypath.hpp:
#ifndef MYPATH_HPP
#define MYPATH_HPP
#include <string>
#include <vector>
namespace my {
template <class T>
class PathBase
{
public:
PathBase();
PathBase(std::string const& p);
std::string String() const;
bool IsSeparator(char c) const;
std::string Separators() const;
typedef std::vector<std::string> pathvec;
protected:
pathvec _path;
private:
virtual std::string _separators() const =0;
};
class Path : public PathBase<Path>
{
public:
Path();
Path(std::string const& p);
private:
virtual std::string _separators() const final;
};
} // namespace 'my'
#endif // MYPATH_HPP
mypath.cpp:
#include "mypath.hpp"
namespace my {
//////////template class PathBase<Path>;
template<>
bool PathBase<Path>::IsSeparator(char c) const
{
return (Separators().find(c) != std::string::npos);
}
template <>
std::string PathBase<Path>::Separators() const
{
return _separators();
}
} // namespace
int main(int argc, char** argv)
{
return 0;
}
Of course I discovered that the code as-written will not compile, since I explicitly specialize Separators() after IsSeparator() has implicitly instantiated it. But I don't particularly want to play whack-a-mole trying to keep all my methods favorably ordered.
While researching similar questions on SO, I found that this accepted answer to one of them suggested that I could solve this problem neatly by merely declaring my specialization. But...
My commented-out template class PathBase<Path>; line in mypath.cpp had no effect on the problem, and
It kinda feels like my header file already declares the explicit specialization with its entire class Path : public PathBase<Path> { ... } declaration.
Exactly what does my explicit declaration need to look like?
Let's get these out of the way first:
template class PathBase<Path>; does not declare an explicit specialization; it is an explicit instantiation definition. You're requesting that the compiler instantiate PathBase<Path> and all its members for which it has definitions, based on the definitions you provided up to that point. In this specific case, it doesn't make any difference indeed.
The declaration of an explicit specialization would look like template<> class PathBase<Path>;, but that's not what you want here either; see below.
The use of PathBase<Path> when defining Path doesn't declare an explicit specialization either; it triggers an implicit instantiation of PathBase<Path>, based on the definition you provided above. An implicit instantiation for a class template instantiates the class definition and only the declarations of its member functions; it doesn't try to instantiate the definitions of the functions; those are only instantiated when needed, later on.
In your cpp file, you're explicitly specializing IsSeparator and Separators for an implicitly instantiated PathBase<Path>. You're requesting that the compiler instantiate PathBase<Path> based on the generic definition you provided, but, when the definitions of those particular functions are needed, use the specific definitions you provide.
It's basically a shorthand alternative to explicitly specializing the whole class template, when the structure of the class and most of the generic definitions for the members are fine, and you only want to fine-tune the definitions of a few members. If you explicitly specialized the whole class template, you'd have to provide a separate class definition and definitions for all the member functions of the specialization, which would mean unnecessary copy-paste.
You need to tell the compiler about those explicit specializations as soon as possible, before there's any chance that some code would attempt to use the definitions (it needs to know that it will have to look for specific definitions instead of generic ones). You do that by declaring (not necessarily defining) the explicit specializations.
The safest place to do that is immediately after the closing brace of the definition of template <class T> class PathBase. Something like:
class Path;
template<> std::string PathBase<Path>::Separators() const;
template<> bool PathBase<Path>::IsSeparator(char c) const;
You definitely need to do this in the header file, not in a cpp file, otherwise other cpp files that use the header will not know about the explicit specializations and will try to instantiate generic versions (if they need them). That will make your program ill-formed, no diagnostic required (this applies to your example as well). What that means is: if the compiler is smart enough to diagnose the problem, you should be grateful; if it isn't, you can't complain, and it's still your fault.
Having declared the explicit specializations up front, the definitions can come later, possibly in a separate cpp file; that's fine, just like for normal functions.
Also note that, should you want to include the definitions for the explicit specializations in the header file (to ease inlining, for example), you'll have to declare them inline, again like for normal functions. Otherwise, including the header in multiple cpp files will make the program ill-formed, NDR (you'll typically get multiple definition errors at link time).
Obligatory standard quote from [temp.expl.spec]/7:
[...] When writing a specialization, be careful about its location; or
to make it compile will be such a trial as to kindle its
self-immolation.
Yes, the members of the standardization committee are human too.
Suppose I've written class template declaration somewhere in collector.h:
template <class T, int maxElements>
class collector {
T elements[maxElements];
int activeCount;
public:
collector();
void process();
void draw();
};
and implementing its three methods in collector.cpp:
template <class T, int maxElements>
collector<T, maxElements>::collector(){
//code here
}
template <class T, int maxElements>
void collector<T, maxElements>::process(){
//code here
}
template <class T, int maxElements>
void collector<T, maxElements>::draw(){
//code here
}
Is there any way of not writing template <class T, int maxElements> and <T, maxElements>
for every function's implementation? Something like that:
template <class T, int maxElements>{
collector<T, maxElements>::collector(){
//code here
}
void collector<T, maxElements>::process(){
//code here
}
void collector<T, maxElements>::draw(){
//code here
}
}
Put the code inside the class definition in the header file.
[You'll probably wind up doing this anyway as soon as you try to build code that uses this class template. See here for background esp. the neglected answer from #Pavel Minaev.]
Nope, you gotta write the template header every time.
Typically, people implement template classes directly inline. They have to have their full source exposed to be used (unless you explicitly instantiate the lot, anyway) so there's little point doing otherwise.
Is there any way of not writing template and for every function's implementation?
No, short of defining template members inline in the class template's definition, there is no way to do that.
The direct answer to your question has been answered by many above.
To know more on whats the best practice, refer to chapter 6 of C++ Templates - The complete guide book. It talks about which is the best place to declare and/or define template class, functions, member functions: in a .h/hpp or .cpp files.
There's always copy & paste!
Unless you have a smart C++ template-aware linker closely coupled to your compiler, you'll have to put the code in-line in the header in any case and the problem goes away. You'll want to do that in any case if the code needs to be portable.
If you really must then there is the somewhat perverse pre-processor macro solution:
#define COLLECTOR_TEMPLATE template <class T, int maxElements>
Explicitly instantiate for all the types you expect to need in the .cpp file so the compiler can generate the code a priori the linker will match the references templkates to the pre-instantiated definitions (see http://www.parashift.com/c++-faq-lite/templates.html#faq-35.13. You will however not be able to instantiate the template for new types.
For separate compilation of templates to work for arbitrarily instantiated classes, the compiler would have to embed the template source in the object file, then when the linker requires a particular instantiation to resolve a reference, it must then extract that source and pass it back to the compiler to generate the instantiated object code, which is then passed back to the linker. This requires the compiler and linker to work hand-in-glove, and for an object file format that supports template source embedding.
Most tool-chains do not support that, so you must either use in-line definition in the header, restrict use of the template to the same source file in which it is defined, or #include the .cpp containing the definition; all three of these are effectively the same thing - making the complete template definition visible to the compiler in a single compilation unit, but the first is the most conventional and flexible solution.
Always considering that the following header, containing my templated class, is included in at least two .CPP files, this code compiles correctly:
template <class T>
class TClass
{
public:
void doSomething(std::vector<T> * v);
};
template <class T>
void TClass<T>::doSomething(std::vector<T> * v) {
// Do something with a vector of a generic T
}
template <>
inline void TClass<int>::doSomething(std::vector<int> * v) {
// Do something with a vector of int's
}
But note the inline in the specialization method. It is required to avoid a linker error (in VS2008 is LNK2005) due to the method being defined more then once. I understand this because AFAIK a full template specialization is the same as a simple method definition.
So, how do I remove that inline? The code should not be duplicated in every use of it. I've searched Google, read some questions here in SO and tried many of the suggested solutions but none successfully built (at least not in VS 2008).
Thanks!
As with simple functions you can use declaration and implementation.
Put in your header declaration:
template <>
void TClass<int>::doSomething(std::vector<int> * v);
and put implementation into one of your cpp-files:
template <>
void TClass<int>::doSomething(std::vector<int> * v) {
// Do somtehing with a vector of int's
}
Don't forget to remove inline (I forgot and thought this solution will not work :) ).
Checked on VC++2005
You need to move specialization definition to CPP file.
Specialization of member function of template class is allowed even if function is not declared as template.
There is no reason to remove the keyword inline.
It does not change the meaning of the code in anyway.
If you want to remove the inline for whatever reason the solution of maxim1000 is perfectly valid.
In your comment, though, it seems you believe that the inline keyword means that the function with all his contents gets always inlined but AFAIK that is actually very much dependent on your compiler optimization.
Quoting from the C++ FAQ
There are several ways to designate that a function is inline, some of
which involve the inline keyword, others do not. No matter how you
designate a function as inline, it is a request that the compiler is
allowed to ignore: the compiler might inline-expand some, all, or none
of the places where you call a function designated as inline. (Don’t
get discouraged if that seems hopelessly vague. The flexibility of the
above is actually a huge advantage: it lets the compiler treat large
functions differently from small ones, plus it lets the compiler
generate code that is easy to debug if you select the right compiler
options.)
So, unless you know that that function will actually bloat your executable or unless you want to remove it from the template definition header for other reasons, you can actually leave it where it is without any harm
This is a little OT, but I thought I'd leave this here in case it helps someone else. I was googling about template specialization which led me here, and while #maxim1000's answer is correct and ultimately helped me figure my problems out, I didn't think it was abundantly clear.
My situation is a little different (but similar enough to leave this answer I think) than the OP's. Basically, I'm using a third party library with all different kinds of classes that define "status types". The heart of these types are simply enums, but the classes all inherit from a common (abstract) parent and provide different utility functions, such as operator overloading and a static toString(enum type) function. Each status enum is different from one another and unrelated. For example, one enum has the fields NORMAL, DEGRADED, INOPERABLE, another has AVAILBLE, PENDING, MISSING, etc. My software is in charge of managing different types of statuses for different components. It came about that I wanted to utilize the toString functions for these enum classes, but since they're abstract I couldn't instantiate them directly. I could have extended each class I wanted to use, but ultimately I decided to create a template class, where the typename would be whatever concrete status enum I cared about. Probably some debate can be had about that decision, but I felt like that was a lot less work than extending each abstract enum class with a custom one of my own and implementing the abstract functions. And of course in my code, I just wanted to be able to call .toString(enum type) and have it print the string representation of that enum. Since all the enums were entirely unrelated, they each had their own toString functions that (after some research I learned) had to be called using template specialization. That led me here. Below is an MCVE of what I had to do in order to make this work correctly. And actually my solution was a bit different than #maxim1000's.
This is a (greatly simplified) header file for the enums. In reality, each enum class was defined in it's own file. This file represents the header files that are supplied to me as part of the library I am using:
// file enums.h
#include <string>
class Enum1
{
public:
enum EnumerationItem
{
BEARS1,
BEARS2,
BEARS3
};
static std::string toString(EnumerationItem e)
{
// code for converting e to its string representation,
// omitted for brevity
}
};
class Enum2
{
public:
enum EnumerationItem
{
TIGERS1,
TIGERS2,
TIGERS3
};
static std::string toString(EnumerationItem e)
{
// code for converting e to its string representation,
// omitted for brevity
}
};
adding this line just to separate the next file into a different code block:
// file TemplateExample.h
#include <string>
template <typename T>
class TemplateExample
{
public:
TemplateExample(T t);
virtual ~TemplateExample();
// this is the function I was most concerned about. Unlike #maxim1000's
// answer where (s)he declared it outside the class with full template
// parameters, I was able to keep mine declared in the class just like
// this
std::string toString();
private:
T type_;
};
template <typename T>
TemplateExample<T>::TemplateExample(T t)
: type_(t)
{
}
template <typename T>
TemplateExample<T>::~TemplateExample()
{
}
next file
// file TemplateExample.cpp
#include <string>
#include "enums.h"
#include "TemplateExample.h"
// for each enum type, I specify a different toString method, and the
// correct one gets called when I call it on that type.
template <>
std::string TemplateExample<Enum1::EnumerationItem>::toString()
{
return Enum1::toString(type_);
}
template <>
std::string TemplateExample<Enum2::EnumerationItem>::toString()
{
return Enum2::toString(type_);
}
next file
// and finally, main.cpp
#include <iostream>
#include "TemplateExample.h"
#include "enums.h"
int main()
{
TemplateExample<Enum1::EnumerationItem> t1(Enum1::EnumerationItem::BEARS1);
TemplateExample<Enum2::EnumerationItem> t2(Enum2::EnumerationItem::TIGERS3);
std::cout << t1.toString() << std::endl;
std::cout << t2.toString() << std::endl;
return 0;
}
and this outputs:
BEARS1
TIGERS3
No clue if this is the ideal solution to solve my problem, but it worked for me. Now, no matter how many enumeration types I end up using, all I have to do is add a few lines for the toString method in the .cpp file, and I can use the libraries already-defined toString method without implementing it myself and without extending each enum class I want to use.
I'd like to add that there is still a good reason to keep the inline keyword there if you intend to leave also the specialization in the header file.
"Intuitively, when you fully specialize something, it doesn't depend on a template parameter any more -- so unless you make the specialization inline, you need to put it in a .cpp file instead of a .h or you end up violating the one definition rule..."
Reference: https://stackoverflow.com/a/4445772/1294184
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.