Reflection on C++ Templates Declaration Everywhere
My Specific Problem
I defined a template class and template functions in MyVector.h and then implemented them in MyVector.cpp. I only wrote template<typename T> once, before the class definition in MyVector.h and again before the first function implementation in MyVector.cpp. This caused compilation to fail.
Later, I added template<typename T> before each function implementation in the implementation file, and included #include "MyVector.cpp" — then the code compiled successfully. Details as follows:
- The code organisation was problematic, which forced me to write
template<typename T>before every function implementation.- For scattered functions, if they use generic types like templates, we must declare
template<typename T>before each function. - If we’re working with a templated class, the
template<typename T>declaration is placed before the class definition, and member functions may not need additional template declarations depending on whether they are defined inside or outside the class. Since in my case they are implemented in a.cppfile, i.e., outside the class, I need to addtemplate<typename T>before every function.
- For scattered functions, if they use generic types like templates, we must declare
- Including different content caused the compilation to fail.
- Directly using
#include "MyVector.cpp"and compiling withg++ main.cpp MyVector.cpp -o myProgramworks fine. - But including only
#include "MyVector.h"and compiling withg++ main.cpp MyVector.cpp -o myProgramresults in a linker error (Undefined symbols for architecture arm64).
- Directly using
Why #include "MyVector.cpp" Is Generally Discouraged
In C++, .cpp files are normally source files, containing implementation code, which are compiled and linked with other object files to create the executable. .h files, on the other hand, are header files that declare interfaces (classes, functions, etc.) for use across multiple source files.
- Multiple Definition Errors:
#include "MyVector.cpp"is equivalent to copying the entire content ofMyVector.cppintomain.cpp.- When I compile with
g++ main.cpp MyVector.cpp -o myProgram,MyVector.cppis compiled twice:- Once because it is included in
main.cppvia#include. - Again because it is explicitly passed in the compilation command.
- Once because it is included in
- This can cause template function implementations to be defined multiple times. The linker may then report errors (e.g., “multiple definition of…”), especially when templates are instantiated. This is similar to an error I encountered in another blog post C++ Include Reflection — the compiler just didn’t throw an error this time because of template class.
- Violation of the Separation of Compilation Principle:
- The standard C++ practice is to place declarations in
.hfiles and implementations in.cppfiles (for non-template code), and use#includeto share interfaces. - Including
MyVector.cppdirectly bypasses the header file, breaks encapsulation and maintainability. Other developers may get confused because.cppfiles are not expected to be directly included.
- The standard C++ practice is to place declarations in
- Lack of Header Guards:
- Header files typically use
#ifndef/#define/#endif(or#pragma once) to prevent multiple inclusion. .cppfiles usually don’t have such guards. IfMyVector.cppis included more than once (directly or indirectly), it may result in multiple definitions or compilation errors.
- Header files typically use
Why the Usual Include Rules Fail Here
In my code, MyVector is a template class, and templates require special handling at compile time.
- Template class implementations must be visible at the point of use:
- C++ templates are instantiated at compile time. When
main.cppusesMyVector<int>, the compiler needs to see the full implementation ofMyVector<int>(including constructor, member functions, etc.) to generate the actual code. - In my case,
main.cpponly sees the declaration (interface) of the template class via#include "MyVector.h". But the implementation (definition) inMyVector.cppis not visible during compilation ofmain.cpp. - When
MyVector.cppis compiled, the compiler doesn’t generate code forMyVector<int>because there is no explicit instantiation for that type. - Therefore, during linking, the linker cannot find the definitions of
MyVector<int>‘s member functions (likeat,push_back, etc.), resulting inUndefined symbolserrors.
- C++ templates are instantiated at compile time. When
- Why does
#include "MyVector.cpp"seem to work?- When I include
MyVector.cppinmain.cpp, the content ofMyVector.cpp(including the template class implementation) is inserted directly intomain.cpp. This allows the compiler to see the full implementation ofMyVector<int>during compilation and generate correct code. - In addition, the compile command
g++ main.cpp MyVector.cpp -o myProgramcompilesMyVector.cppagain, but since template class definitions usually don’t generate duplicated symbols (they’re instantiated on-demand), the linker doesn’t complain. This is just a lucky coincidence, not a best practice. - Moreover, including
.cppfiles like#include "MyVector.cpp"is considered bad practice. It breaks modularity and may cause issues in larger projects.
- When I include
Solutions to My Problem
1. Put Template Declarations and Implementations in the Header File (Recommended)
Since MyVector is a template class, the simplest and most recommended approach is to put both the declaration and the implementation in the MyVector.h file. This avoids the complexity of separated compilation and ensures that the compiler always sees the full implementation when instantiating the template.
MyVector.h:
1 |
|
main.cpp:
1 |
|
Compile Command:
1 | g++ main.cpp -o myProgram |
This approach:
- Avoids the problem of
#include "MyVector.cpp". - Ensures template implementation is visible to the compiler.
- Follows common best practices for C++ templates.
2. If I Have to Insist on Separating .h and .cpp
If we really want to put the template implementation in MyVector.cpp, make sure to:
- Add
template<typename T>before each member function definition. - Ensure the implementation is visible to the compiler during template instantiation.
MyVector.h:
1 |
|
MyVector.cpp:
1 |
|
main.cpp:
1 |
|
Still Fails With This Compile Command:
1 | g++ main.cpp MyVector.cpp -o myProgram |
But this still leads to linker errors, because when compiling main.cpp, the compiler only sees the declaration in MyVector.h, and not the implementation in MyVector.cpp. To solve this, there are two possible approaches:
Add Explicit Instantiation in
MyVector.cpp1
2
3
4
5
6
7
8
9
template<typename T>
void MyVector<T>::someFunction(T value) {
// implementation
}
template class MyVector<int>; // Explicit instantiation
// The drawback is that the template will only work for explicitly instantiated types (e.g., `int`), losing the generic flexibility of templates.Use
#include "MyVector.cpp"to make the compiler aware of the template function implementationsThis is what I did to make it compile, but it is not recommended, because the compile command also includes
MyVector.cpp, which causes it to be compiled twice. This only hides the real problem.1
g++ main.cpp MyVector.cpp -o myProgram
Conclusion
- When we’re working with a templated class, make sure to put both declaration and implementation in
ClassName.hfiles - Still stick to the rule that include
.hbut compile the.cppas a general rule
- Title: Reflection on C++ Templates Declaration Everywhere
- Author: Ricardo Pu
- Created at : 2025-04-19 19:34:28
- Updated at : 2025-04-20 14:53:22
- Link: https://ricardopotter.github.io/RicardoBlog/2025/04/19/Reflection-on-CPP-Templates-Declaration-Everywhere/
- License: This work is licensed under CC BY-NC-SA 4.0.