This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why can templates only be implemented in the header file?
I've struggled with this for a while, and I've taken a look to several questions here, but being new to C++ I haven't been able to understand where I am wrong.
Here is the code, I took it from this page and tried to make it work, but so far I haven't been lucky:
stack.h
#ifndef STACK_H
#define STACK_H
template <class T>
class Stack {
public:
Stack(int n);
~Stack() { delete[] s; };
private:
T* s;
int _top;
int _size;
};
#endif // STACK_H
stack.cpp
#include "stack.h"
template <class T>
Stack<T>::Stack(int n) {
_size = n;
_top = -1;
s = new T[_size];
}
main.cpp
#include <iostream>
#include "stack.h"
using namespace std;
int main() {
Stack<int> s(10); // undefined reference to `Stack<int>::Stack(int)'
return 0;
}
When I compile (gcc 4.5.2) I get one error: undefined reference to Stack<int>::Stack(int). I've tried several things but without any real knowledge to support what I do. I will be really thankful if somebody can explain me what's going on.
You can only have a template class definition in a cpp file if it's a specialized definition - i.e. you know what T is.
Other than that, and your case belongs here, all definitions of your template class have to go in the header file. The compiler has to know about these each time a new instance is declared or defined because the type, and thus the behavior, changes. Definitions in a cpp file would mean a different translation unit, so the compiler couldn't possibly know about the behavior for every single T you try to apply to your template.
There is nothing to compile in "stack.cpp". Templates are only compiled when they are instantiated. Hence the linker cannot find this function which was never compiled.
You can't really separate declarations and implementations in header and source files with templates.
What you can do is copy-n-paste "stack.cpp" to the end of "stack.h". Alternatively include "stack.cpp" at the end of "stack.h", not the other way round, which achieves the same effect. In the latter case it might be wise to change the extension of the "cpp" file (see Including .cpp at end of template header file)
The compiler has to have all of the pertinent information when creating template classes and consequently templates are generally fully implemented in their header files.
There are several ways you could accomplish this, inline functions, defining the template functions in the header file, including your implementation in a separate file (at the end of your header file, with #include), etc.
Here's a similar question with more details.
Related
I'm trying to create a library for a school work, and I've been wondering if it is safe to declare a templated class on the main header file containing the class definition and method declarations, but then separating the method definitions in a different header file?
Because I have been able to do this in my example below, but I don't know if it will cause me some problems in the long run.
main program
// main.cpp
#include <iostream>
#include "declaration.hpp"
int main()
{
card<int> a(5);
std::cout<<a.getID()<<'\n';
return 0;
}
main header file
in this header file, only the class definition and the declaration of the method getID() is written but not it's definition, and by the end of the class I included the other header file that contains the method definitions.
// declaration.hpp
#ifndef DEC_HPP
#define DEC_HPP
#include <iostream>
template<typename T>
class card
{
public:
T id;
card(const int id) : id(id) {}
T getID();
};
#include "definition.hpp"
#endif
method definitions
This header file contains the method definition of getID() from the main header.
I also included the "declaration.hpp" in this header, and this is the part where I'm not so sure of, because I included both files together with each other.
// definitions.hpp
#ifndef DEF_HPP
#define DEF_HPP
#include <iostream>
#include "declaration.hpp"
template<typename T>
T card<T>::getID()
{
return id;
}
#endif
I have compiled this program and it's working on my machine, but I just wanted to know if this way of isolating my code will cause me some errors in the future, I don't want to put my templated class definitions in a cpp files because I find it hard to maintain.
This is indeed a better approach because it makes your code look simple and better. Moreover, it is the main reason why header file is used.
Your main header file will simply tell that what functions/classes are you using and without even viewing your code, anyone can guess if you are working correctly or not.
There wont be any safety issues at all.
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 5 years ago.
I am fairly new to c++ and have not had much experience with headers or templates, and I have not had any experience with them combined. So, I have run into problems trying to use the class I have created. My class definitions and headers are as follows:
J.h is the header file for the template class J.
#ifndef J_H
#define J_H
template<class t>
class J {
public:
void speak();
};
#endif
J.cpp has the function definitions for it's header.
#include "J.h"
#include <iostream>
template<class T> void J<T>::speak(){
std::cout << "Hello from j";
}
main.cpp has the main function and tries to use J.
#include "J.h"
int main(){
J<int> j;
j.speak();
}
My problem is that when I compile with g++ J.h J.cpp main.cpp, I get the error undefined reference to J<int>::speak(), but doing g++ J.h J.cpp runs without any error. I am very new to templates, so any help is appreciated. Thank you in advance.
Just put your implementation in the header file instead.
There was once standard that allow putting template implementation in its own source file (template export) but compiler supporting this feature was rare (Comeau was the only one I believe?).
IIRC, template export was even deprecated in C++1x.
After a fair deal of research I understand why templates classes cannot be separated into header and source files traditionally.
However, this (Why can templates only be implemented in the header file?) seems to imply that you can still have a sort of pseudo-separate-compilation process by including the implementation file at the end of the header file as shown below:
// 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
}
With the explanation "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."
However, when I do that, I get multiple errors stating it is a redefinition of a constructor/method/function. I have been able to prevent this by putting include guards on the .cpp files which seems like bad practice.
My main questions would then be:
What is the proper way to do this with the implementation include at the bottom of the header file?
Would the include guards on my .cpp file prevent the compiler from creating the templates class/function for other types since it can now only be included once?
Isn't part of the reason for using header files in the first place is to prevent code from being recopied every time it is included, to keep a short compilation time? So what is the performance effect of templated functions (since they have to be defined in header) versus simply overloading a function/class? When should each be used?
Below is an abridged version of code for my own simple Node struct:
// Node.hpp
#ifndef NODES_H
#define NODES_H
#include <functional>
namespace nodes
{
template<class Object>
struct Node
{
public:
Node(Object value, Node* link = nullptr);
void append(Node tail);
Object data;
Node* next;
};
template<class Object> void prepend(Node<Object>*& headptr, Node<Object> newHead);
}
// Forward 'declaration' for hash specialization
namespace std
{
template <typename Object>
struct hash<nodes::Node<Object>>;
}
#include "Node.cpp"
#endif
// Node.cpp
// #ifndef NODE_CPP
// #define NODE_CPP
#include "Node.hpp"
template<class Object>
nodes::Node<Object>::Node(Object value, Node* link): data(value), next(link) {}
template<class Object>
void nodes::Node<Object>::append(Node tail) {
Node* current = this;
while (current->next != nullptr) {
current = current->next;
}
current->next = &tail;
}
template<class Object>
void nodes::prepend(Node<Object>*& headptr, Node<Object> newHead) {
Node<Object>* newHeadPtr = &newHead;
Node<Object>* temporary = newHeadPtr;
while (temporary->next != nullptr) {
temporary = temporary->next;
}
temporary->next = headptr;
headptr = newHeadPtr;
}
namespace std
{
template <typename Object>
struct hash<nodes::Node<Object>>
{
size_t operator()(nodes::Node<Object>& node) const
{
return hash<Object>()(node.data);
}
};
}
// #endif
What is the proper way to do this with the implementation include at the bottom of the header file?
Put the include guards into your header file, including the implementation #include directive:
#ifndef __FOO_H
#define __FOO_H
// Foo.h
template <typename T>
struct Foo
{
void doSomething(T param);
};
#include "Foo.tpp"
#endif
You may also add the guards to Foo.tpp, but in the situation you posted it will not make much sense.
Would the include guards on my .cpp file prevent the compiler from creating the templates class/function for other types since it can now only be included once?
Typically you don't need include guards in *.cpp files at all, as you don't include them anywhere. Include guards are only needed in those files which are included into multiple translation units. And of course, those guards will not prevent instantiating the templates for other types, since it is what templates are designed for.
Isn't part of the reason for using header files in the first place is to prevent code from being recopied every time it is included, to keep a short compilation time? So what is the performance effect of templated functions (since they have to be defined in header) versus simply overloading a function/class? When should each be used?
Here you raise a big, platform-dependent and a bit opinion-based topic. Historically, include files were used to prevent code copying, as you said. It was enough to include function declarations (headers, not definitions) into multiple translation units, and then link them with a single copy of the compiled code for included functions.
Templates compile much slower than non-template functions, so implementing template export (separate header/implementation compilation for templates) isn't worth saving compilation time.
For some discussions and good answers on template performance, check these questions:
Is Template Metaprogramming faster than the equivalent C code?
C++ templates for performance?
Do c++ templates make programs slow?
In short, sometimes templates allow you to make some decisions in compile time instead of runtime, making the code faster. Anyway, the only proper way to determine if the code became faster or not, is to run performance tests in real-world environment.
Finally, templates are more about design, not about performance. They allow you to significantly reduce code duplication and conform DRY principle. A banal example of it are functions like std::max. A more interesting example is Boost.Spirit, which uses templates for building parsers entirely in compile time.
guys, this is my first question in StackOverflow so forgive me if make any mistake.
I am writing a small project which contains 2 source files and 3 header files.
// some_template_functions.h
#ifndef SOME_TEMPLATE_FUNCTION_H
#define SOME_TEMPLATE_FUNCTION_H
template <typename T>
int getvalue(string line, string key, T & val)
{
// method to get value (all the types except string) from line using key
}
template <>
int getvalue<string>(string line, string key, string &val)
{
// method to get some string from line using key, similar to getvale<int>
// but with slight difference to handle some special characters
}
#endif
//myclass.h
#ifndef MYCLASS_H
#define MYCLASS_H
#include "some_template_functions.h"
class MYCLASS
{
//declarations of constructors, member functions and members
double member_double;
string member_string;
}
#endif
//myclass.cpp
#include "myclass.h"
MYCLASS:MYCLASS()
{
// for each member
// using "getvalue" defined in "SOME_TEMPLATE_FUNCTION.H" to get the values
getvalue(line, key, member_double);
getvalue(line, key, member_string);
}
//main.cpp
#include "myclass.h"
#include "some_template_functions.h"
int main()
{
myclass A;
int some_value;
getvalue(line, key, value);
return 0;
}
I have no problem compiling the main.o and myclass.o but it is just when I was trying to link the two object files I got error message like:
myclass.cpp: multiple definition of int getvalue<std::basic_string><char, std::char_traits<char>, ...> and etc.
/tmp/cc22zEow.o:main.cpp: first defined here
collect2: ld returned 1 exit status
I know the reason probably is because I am including "some_template_function.h" in both myclass.h and main.cpp, each myclass.o and main.o is going to have its own definition of getvalue which is causing the problem. If I change
#include "some_template_functions.h"
to
#ifndef SOME_TEMPLATE_FUNCTIONS_H
#define SOME_TEMPLATE_FUNCTIONS_H
#endif
the constructors of MYCLASS is not goint to work.
I plan to expand the "some_template_functions.h" and its .cpp file in the future so if possible I would like to keep them separated from the other files. And because the way I am declaring function "getvalue" my attempt to move its definition to .cpp file was not working out for me very well.
I've tried to solve this problem for days but since I just start to learn C++ so far I could not get this right. So please, any suggestions will be appreciated! Thanks in advance!
The specialization of getvalue<std::string>(...) isn't a template and, thus, not implicitly inline. If you want to define this function in a header, e.g., because it is close to trivial and should be inlined, you'll need to mark it explicitly as inline. If the function does anything non-trivial it may be worth merely declaring the specialization in the header and defining it in a suitable translation unit.
Here are the files I am working on:
class.h
#include <vector>
using std::vector;
template<class T>
class test {
private:
vector<T> data;
public:
typedef vector<T> vt;
typedef typename vt::iterator it;
test() {
}
;
it find(T x);
}
and class.cpp
#include "class.h"
it test::find(T x) {
return find(data.begin(), data.end(), x);
}
The codes work if I put the implementation of find inside the class declaration.
However, when I separate the implementation from the class, the compiler reports an error "expected initializer before test".
How to fix it? Is the problem related to the scope of typedef/typename?
Sorry for my poor English, it is my secondary language.
Please point out any error in my codes as well as my english
Thank you for your help.:D
When the compiler sees it, it can't yet know that you mean test<T>::it. So you have to tell it:
template<class T> typename test<T>::it test<T>::find(T x) {
// The following line doesn't compile, but that's another issue:
// return find(data.begin(), data.end(), x);
}
See http://ideone.com/Rtho2 for a working program.
Now templates in C++ violates this principle, bcoz C++ is a compiled language. And compiler generates all the needed code during compilation. Now to adhere to OOP we end up with fragile templates which not 100% generic in nature.
Keep declaration and definitions separate (SHARING implementation)
If you are just want to keep things clean and in order, then you can include your implementation file in another header. I think it should be header file as this goes with basic convention that we share .h files and we keep .cc files not to be shared (until you are sharing the code itself). Here is how the files look.
foo.h
This is simple file with including foo_impl.h.
#ifndef FOO_H
#define FOO_H
template <class T>
class Foo {
public:
Foo (T);
T get();
private:
T data;
};
#include "foo_impl.h"
#endif
foo_impl.h
This one is bit different from the norms. Here we are not guarding the header file content. Instead we will raise an error if some one included foo_impl.h directly (which in our case does not make sense).
#ifndef FOO_H
#error 'foo_impl.h' is not supposed to be included directly. Include 'foo.h' instead.
#endif
template <class T>
Foo <T> :: Foo (T stuff) {
data = stuff;
}
template <class T>
T Foo <T> :: get () {
return data;
}
Now if some one tries to include foo_impl.h directly will get error like:
foo_impl.h:2:2: error: #error 'foo_impl.h' is not supposed to be included directly. Include 'foo.h' instead.
PROS:
Separation of concerns, implementation and declarations are in separate files.
Safe guarding implementation file avoid accidental inclusion.
The header file used to include is not bloated with implementation code.
CONS:
As mentioned above, have to share the implementation.
Keep declaration and definitions separate (NOT SHARING implementation)
For not sharing code for templates, you have to define all the possible datatypes your template can be used with in .cc/.cpp file like:
template class foo< int >;
template class foo< double >;
PROS:
Separation of concerns, implementation and declarations are in separate files.
No need to share your implementation
CONS:
Not too generic. Have to know before hand what is required.