Storing C++ template function definitions in a .CPP file
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.
Why can templates only be implemented in the header file?
Caveat: It is not necessary to put the implementation in the header file, see the alternative solution at the end of this answer.
Anyway, the reason your code is failing is that, when instantiating a template, the compiler creates a new class with the given template argument. For example:
template<typename T>
struct Foo
{
T bar;
void doSomething(T param) {/* do stuff using T */}
};
// somewhere in a .cpp
Foo<int> f;
When reading this line, the compiler will create a new class (let's call it FooInt
), which is equivalent to the following:
struct FooInt
{
int bar;
void doSomething(int param) {/* do stuff using int */}
}
Consequently, the compiler needs to have access to the implementation of the methods, to instantiate them with the template argument (in this case int
). If these implementations were not in the header, they wouldn't be accessible, and therefore the compiler wouldn't be able to instantiate the template.
A common solution to this is to write the template declaration in a header file, then implement the class in an implementation file (for example .tpp), and include this implementation file at the end of the header.
Foo.h
template <typename T>
struct Foo
{
void doSomething(T param);
};
#include "Foo.tpp"
Foo.tpp
template <typename T>
void Foo<T>::doSomething(T param)
{
//implementation
}
This way, implementation is still separated from declaration, but is accessible to the compiler.
Alternative solution
Another solution is to keep the implementation separated, and explicitly instantiate all the template instances you'll need:
Foo.h
// no implementation
template <typename T> struct Foo { ... };
Foo.cpp
// implementation of Foo's methods
// explicit instantiations
template class Foo<int>;
template class Foo<float>;
// You will only be able to use Foo with int or float
If my explanation isn't clear enough, you can have a look at the C++ Super-FAQ on this subject.
Definition of a template function inside .cpp file is not working even though I am instantiating a dummy object in .cpp file
Your first question was why writing:
template<> class myclass <int>;
causes an undefined reference error. The answer is that template<>
declares an explicit specialization: it's saying that there is a special definition of myclass<int>::doSomething
that takes the place of the generic definition earlier in the file. However, the definition of the specialization is not provided. Therefore, no definition of myclass<int>::doSomething
is emitted when template.cpp
is translated.
Your second question was why replacing the explicit instantiation with:
myclass <int> obj;
in template.cpp
did not cause myClass<int>::doSomething
to be emitted from that translation unit. The answer is twofold:
When the compiler implicitly instantiates
myclass<int>
when translatingtemplate.cpp
, it does not implicitly instantiatemyclass<int>::doSomething
because, at that point, the function's definition is not yet needed.Even if the compiler were to implicitly instantiate
myclass<int>::doSomething
during the translation oftemplate.cpp
, that implicit instantiation is NOT guaranteed to make that instantiated definition available to other translation units. (The compiler may, in effect, generate it with internal linkage.)
See C++17 [temp]/7
A function template, member function of a class template, variable template, or static data member of a
class template shall be defined in every translation unit in which it is implicitly instantiated (17.7.1) unless
the corresponding specialization is explicitly instantiated (17.7.2) in some translation unit; no diagnostic is
required.
What this is saying is that if you need to call a function template from translation unit 1, but you only want to define that function template in translation unit 2, then translation unit 2 must explicitly instantiate the function template with the desired arguments. An implicit instantiation doesn't count.
(Note that the explicit instantiation of myclass<int>
will also implicitly instantiate the definitions of all of myclass<int>
's member functions.)
Related Topics
How Does Delete[] "Know" the Size of the Operand Array
Usr/Bin/Ld: Cannot Find -L≪Nameofthelibrary≫
Explicit Template Instantiation - When Is It Used
Benefits of Inline Functions in C++
How Approximation Search Works
How to Convert a Number to String and Vice Versa in C++
Why Is Address of Char Data Not Displayed
Define Preprocessor Macro Through Cmake
What Is the Lifetime of a Static Variable in a C++ Function
What's the Most Efficient Way to Erase Duplicates and Sort a Vector
Initialization of All Elements of an Array to One Default Value in C++
What Are the Advantages of List Initialization (Using Curly Braces)
Function Does Not Change Passed Pointer C++
Using Generic Std::Function Objects With Member Functions in One Class
Using G++ to Compile Multiple .Cpp and .H Files
How to Replace All Occurrences of a Character in String