C++ Template Class Problem - c++

Hi everybody I just wanted to practice some c++ template but i get linker errors. Can anybody help me please?
Here is my code:
// File: MyClass.h
#ifndef _MYCLASS_H
#define _MYCLASS_H
template<class T> class MyClass {
T value;
public:
MyClass(T v);
~MyClass();
};
#endif // _MYCLASS_H
// File: MyClass.cpp
#include "MyClass.h"
template<class T> MyClass<T>::MyClass(T v) {
value = v;
}
template<class T> MyClass<T>::~MyClass() {
}
// File: main.cpp
#include "MyClass.h"
int main() {
MyClass<int> test(10);
return 0;
}
Here is command line output:
g++ main.cpp -c
g++ MyClass.cpp -c
g++ main.o MyClass.o -o Out
main.o: In function `main':
main.cpp:(.text+0x1a): undefined reference to `MyClass<int>::MyClass(int)'
main.cpp:(.text+0x2b): undefined reference to `MyClass<int>::~MyClass()'
collect2: ld returned 1 exit status
make: *** [all] Error 1
As you can see I'm using Ubuntu 10.04 and GNU C++ Compiler.
Am I missing something in this code?
Thanks for replies. It works but isn't there a better way to protect the code?
For example what if I want to create a non-opensource library?!
I want to export the code to a static library. and link the library to other projects ...

You have to put full template into the header. Compiler needs to see the body of the template methods at the site of template instantiation - main.cpp in your case. See, for example, C++ FAQ.

You should put template classes and inline methods into header files. You can't seperate definition and implementation in their case.

#Nikolai N Fetissov has the right solution. I would add to this that a nice way to do this, if you want to keep the implementation and templated function definitions separate is that you can put the implementations into MyClass.hxx and include it at the end of your MyClass.h
// File: MyClass.h
#ifndef _MYCLASS_H
#define _MYCLASS_H
template<class T> class MyClass
{
T value;
public:
MyClass(T v);
~MyClass();
};
#include "MyClass.hxx" /// <--- like this
#endif // _MYCLASS_H

It's important to remember what a template is. It is a template for generating code if needed; it is not code itself.
So declaring a template class and writing implementations for those methods does not generate any object code for that class; it simply provides a template for doing so if necessary.
When a template class is instantiated with an actual argument, the compiler will generate the code from the template class. In order to do that, it needs to be able to see the the templates. But since you've only #includeed the .h file, and the implementation of the methods in in the .cpp file, the compiler won't be able to generate the object code for the function implementations. Then, when the linker looks for those definitions it won't find it.
All of this is a long-winded way of getting to the same result the other answers did -- you need to put the implementation in the header file with the class declaration. But it may help to know why that is.

Related

Error: Multiple definitions of function in C++ class [duplicate]

This question already has answers here:
Separating class code into a header and cpp file
(8 answers)
Closed 5 months ago.
I don't know how to add functions of a class outside its scope to it, use them in another class and then compile it.
MyMain.cpp
#include"MyClass.cpp"
int main(){
MyClass myClass;
myClass.run();
}
MyClass.cpp
#ifndef MYCLASS_CPP
#define MYCLASS_CPP
#include<iostream>
class MyClass {
private:
void usage();
public:
void run();
};
void MyClass::usage(){
std::cout << "usage called" << std::endl;
}
void MyClass::run(){
usage();
}
#endif
I try to compile it with:
g++ MyMain.cpp MyClass.cpp -o main
With that I get the following error message:
/usr/bin/ld: /tmp/ccN7GfOD.o: in function `MyClass::usage()':
MyClass.cpp:(.text+0x0): multiple definition of `MyClass::usage()'; /tmp/ccLhxS6v.o:MyMain.cpp:(.text+0x0): first defined here
/usr/bin/ld: /tmp/ccN7GfOD.o: in function `MyClass::run()':
MyClass.cpp:(.text+0x38): multiple definition of `MyClass::run()'; /tmp/ccLhxS6v.o:MyMain.cpp:(.text+0x38): first defined here
collect2: error: ld returned 1 exit status
If I have understood the concept correctly, the function headers within the class serve only as placeholders. The actual functionality is then "overwritten" by the external functions, which also contain a body.
And why does the error message say, that the function is already defined in the MyMain.cpp?
I have also seen that there are many similar questions here, but unfortunately I could not expand my understanding of the basic problem to solve it.
Is it possible that I am using the command to build the class with C++ incorrectly or that I can save the #include "MyClass.cpp"?
Kind regards
Several things wrong. here's the steps to put it right
Rename MyClass.cpp to MyClass.h.
Create a new empty file MyClass.cpp
Move the function definitions MyClass::usage() { .. } and MyClass::run() { .. } from MyClass.h to MyClass.cpp. You should probably also move #include <iostream> but this is not essential.
Add #include "MyClass.h" to MyClass.cpp
Change #include "MyClass.cpp" to #include "MyClass.h" in MyMain.cpp
Then build as you are doing now. That part is correct.
Essentially the technique is to separate your code into declarations and definitions. The declarations go into header files, which are included in the cpp files. The cpp files contain the definitions and are what you compile.

c++ linker error - 'undefined reference' to not inline defined functions

For few days I'm trying to compile one project written in C++ using Code::Blocks IDE (on Linux, Ubuntu 64-bit). Code is valid but there are some linker errors. I noticed that I get errors 'undefined reference' for functions which are not inline defined in classes and are in other files (class is i *.h file and definitions on these functions are in *.cpp). I tried to write my own Makefile but it didn't help.
Makefile:
all: project
project: main.o DList.o Person.o
g++ main.o DList.o Person.o -o project
main.o: main.cpp
g++ -c main.cpp
DList.o: include/DList.cpp
g++ -c include/DList.cpp
Person.o: include/Person.cpp
g++ -c include/Person.cpp
clean:
rm -rf *.o
I don't know what should I do although I read some about these errors on the net.
// EDIT
I changed Object.cpp and Object.h to Person.cpp and Person.h, moved *.cpp files to main directory and changed #include paths in *.cpp files.
Errors:
obj/Debug/main.o||In function `main':|
...main.cpp|19|undefined reference to `DListIterator<Person>::go(int)'|
...main.cpp|20|undefined reference to `std::basic_ostream<char, std::char_traits<char> >& operator<< <Person>(std::basic_ostream<char, std::char_traits<char> >&, DList<Person>&)'|
...main.cpp|21|undefined reference to `DList<Person>::~DList()'|
...main.cpp|21|undefined reference to `DList<Person>::~DList()'|
obj/Debug/main.o||In function `DList<Person>::insert(Person&)':|
...include/DList.h|45|undefined reference to `DList<Person>::insert(Person&, DListIterator<Person>&)'|
||=== Build finished: 5 errors, 0 warnings ===|
It makes no difference if I build starting make in command line or using Build function in Code::Blocks.
When I copied all code from *.cpp files to *.h files, compiler returned no errors, so I think that it's only linker problem.
It looks like you are attempting to separately compile a template. This is not possible in general, as a template will only be instantiated when it is used, and it is never used in the DList.cpp file. Try one of two things:
Move the definitions of the functions in DList into the header file (this is the normal way of doing things).
Put some explicit instantiations of DList in to the DList.cpp file. (Example: template class DList<Person>;)
Full example of the problem: Currently you have:
//DList.h
template<typename T>
class DList {
void insert(T& newPerson);
//etc
};
//DList.cpp
#include "DList.h"
//The when this is being compiled,
//the compiler does not know about Person,
//so it cannot instantiate this function.
template<typename T>
void DList<T>::insert(T& newPerson) {
//implementation
}
//etc
//main.cpp
#include "DList.h"
#include "Person.h"
int main() {
//When this is being compiled, it does not know the
//definition of the out-of-line functions in `DList`,
//so it cannot instantiate them.
DList<Person> people;
people.insert(Person("Joe"));
}
One possible fix is to remove DList.cpp and put the definitions in "DList.hpp":
//DList.hpp
template<typename T>
class DList {
void insert(T& newPerson) {
//implementation
}
~DList();
//etc
};
//the implementations can alternatively be
//placed outside the class, but in the header:
template<typename T>
DList<T>::~DList() {
//implementation
}
The other fix is to explicitly instantiate DList (in a compilation unit where the definitions are available):
//DList.cpp
#include "DList.h"
#include "Person.h"
template<typename T>
void DList<T>::insert(T& newPerson) {
//implementation
}
//Explicit instantiation:
template class DList<Person>;

Multiple Template Instantiation

I'm designing a CUDA-C++ library with template classes. There are template functions my classes use, and they are invisible to main as well as the user. I need to specialize them explicitly because of the two steps of compiling to be performed, otherwise I'd get an "unresolved external" error when linking. Being this classes used in main.cpp, there's no way (I guess...) to tell nvcc what types are going to be used in tha main program, so I thought of using some macros to specialize them. Here's a simplified versione of the code:
//CUDA_functions.h
// CUDA functions declared here and included in files that will be compiled
// with g++. Those functions are implemented in .cu files, compiled with nvcc
template <typename T>
void foo1(T x);
template <typename T>
void foo2(T x);
template <typename T>
void foo3(T x);
//fileA.h - included in main.cpp
#include "CUDA_functions.h"
template <typename T>
class A {
// it uses foo1 & foo2 inside
}
//fileB.h - included in main.cpp
#include "CUDA_functions.h"
template <typename T>
class B {
// it uses foo1 & foo3 inside
}
//macros.h
#define _USE_CLASS_A(T) template void foo1(T); \
template void foo2(T); /**/
#define _USE_CLASS_B(T) template void foo1(T); \
template void foo3(T); /**/
//user_spec.cu - template specializations by user. This is the first file to be
// - compiled and it doesn't know what classes are going to be used
// say, user wants to use classes A & B: HERE THE ERROR RAISES!
#include "macros.h"
_USE_CLASS_A( int );
_USE_CLASS_B( int );
When I compile this code with Visual Studio, I get a warning about the double explicit instantiation (foo1), but when I compile it with g++ warning becomes an error!
I can't write macros like
#define _USE_FOO1(T) template void foo1(T) /**/
#define _USE_FOO2(T) template void foo2(T) /**/
#define _USE_FOO3(T) template void foo3(T) /**/
because the user doesn't have to worry about the existence of those functions and I'd like to specialize a list of them based on what class he/she is going to use. Last but not least, I found nothing about a "conditional specialization" of template. What can I do to solve? Thanks to everyone would be so nice to answer. Bye.
Is it for host code or device code? I believe CUDA does not support linking for device code. Linking template functions in host code has always been a bit fishy, CUDA or no CUDA.
Instead of having your hands dirty with macros -- how about putting them in a header, inside of namespace detail?
By convention, detail namespace indicates library internal stuff that you shouldn't ever access as a user.

Separate compiling with MinGW

Using this tutorial Makefile I want to build a simple program with a separate compiling, The main problem is that the IDE Eclpse Indigo C\C++ (prespective) or MinGW I cannot compile the files. The error which I get is :
undefined reference to double getAverage<int, 85u>(int (&) [85u])'
undefined reference to int getMax<int, 85u>(int (&) [85u])'
undefined reference to int getMin<int, 85u>(int (&) [85u])'
undefined reference to void print<int, 85u>(int (&) [85u])'
undefined reference to void sort<int, 85u>(int (&) [85u])'
undefined reference to void print<int, 85u>(int (&) [85u])'
The main.cpp file is this :
#include "Tools.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
int numbers[] = {1,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8};
cout <<"Average = "<< getAverage(numbers) << endl;
cout <<"Max element = "<< getMax(numbers) << endl;
cout <<"Minimal element = "<< getMin(numbers) << endl;
print(numbers);
sort(numbers);
print(numbers);
return 0;
}
and I have a Tools.h file :
#ifndef TOOLS_H_
#define TOOLS_H_
#include <iostream>
int getBigger(int numberOne,int numberTwo);
template <typename T,size_t N> double getAverage(T (&numbers)[N]);
template <typename T,size_t N> T getMax(T (&numbers)[N]);
template <typename T,size_t N> T getMin(T (&numbers)[N]);
/**
* Implementing a simple sort method of big arrays
*/
template <typename T,size_t N> void sort(T (&numbers)[N]);
/**
* Implementing a method for printing arrays
*/
template <typename T,size_t N> void print(T (&numbers)[N]);
#endif
When you compile Tools.cpp your compiler has no idea about the template parameters that you have used in main.cpp. Therefore it compiles nothing related to this templates.
You need to include theses template definitions from the compilation unit that uses them. The file Tools.cpp is often renamed to something like Tools.inl to indicate that it's neither a header file nor a separate compilation unit.
The compilation unit "main.cpp" could look like this:
#include "tools.h"
#include "tools.inl"
main()
{
int number[] = {1,2,3};
getaverage(numbers);
}
Since the compiler identifies the required specialization it can generate the code from the implementation file.
For most cases, harper's answer is appropriate. But for completeness' sake, explicit template instantiation should also be mentioned.
When you include the implementation in every compilation unit, your template classes and functions will be instantiated and compiled in all of them. Sometimes, this is not desirable. It is mostly due to compile-time memory restrictions and compilation time, if your template classes and functions are very complicated. This becomes a very real issue when you, or the libraries you use rely heavily on template metaprogramming. Another situation could be that your template function implementations might be used in many compilation units, and when you change the implementation, you will be forced to re-compile all those compilation units.
So, the solution in these situations is to include a header file like your tools.h, and have a tools.cpp, implementing the templates. The catch is that, you should explicitly instantiate your templates for all the template arguments that will be used throughout your program. This is accomplished via adding the following to tools.cpp:
template double getAverage<int,85>(int (&numbers)[85]);
Note: You obviously have to do something about that "85", such as defining it in a header file and using it across tools.cpp and main.cpp
I've found this article which is useful : templates and header files
I declared the function in the Tools.h file and include there the file Tool.hpp and after this I defined them in the Tools.hpp file.
I haven't tried to compile .cpp and .c files together but maybe my example will help.
I had similar problem compiling two separate assembly files .s on mingw with standard gcc
compiler and i achieved it as follows:
gcc -m32 -o test test.s hello.s
-m32 means i'm compiling 32bit code
-o is the output file ( which in my example is the "test" file )
test.s and hello.s are my source files. test.s is the main file and hello.s has the helper function. (Oh, to mention is the fact that both files are in the same directory)

"Undefined symbols" linker error with simple template class

Been away from C++ for a few years and am getting a linker error from the following code:
Gene.h
#ifndef GENE_H_INCLUDED
#define GENE_H_INCLUDED
template <typename T>
class Gene {
public:
T getValue();
void setValue(T value);
void setRange(T min, T max);
private:
T value;
T minValue;
T maxValue;
};
#endif // GENE_H_INCLUDED
Gene.cpp
#include "Gene.h"
template <typename T>
T Gene<T>::getValue() {
return this->value;
}
template <typename T>
void Gene<T>::setValue(T value) {
if(value >= this->minValue && value <= this->minValue) {
this->value = value;
}
}
template <typename T>
void Gene<T>::setRange(T min, T max) {
this->minValue = min;
this->maxValue = max;
}
Using Code::Blocks and GCC if it matters to anyone. Also, clearly porting some GA stuff to C++ for fun and practice.
The template definition (the cpp file in your code) has to be included prior to instantiating a given template class, so you either have to include function definitions in the header, or #include the cpp file prior to using the class (or do explicit instantiations if you have a limited number of them).
Including the cpp file containing the implementations of the template class functions works. However, IMHO, this is weird and awkward. There must surely be a slicker way of doing this?
If you have only a few different instances to create, and know them beforehand, then you can use "explicit instantiation"
This works something like this:
At the top of gene.cpp add the following lines
template class Gene<int>;
template class Gene<float>;
In if(value >= this->minValue && value <= this->minValue) the second minValue should be maxValue, no?
Echo what Sean said: What's the error message? You've defined and declared the functions, but you've not used them in anything anywhere, nor do I see an error (besides the typo).
TLDR
It seems that you need an Explicit Instantiation i.e. to actually create the class. Since template classes are just "instructions" on how to create a class you actually need to tell the compiler to create the class. Otherwise the linker won't find anything when it goes looking.
The thorough explanation
When compiling your code g++ goes through a number of steps the problem you're seeing occurs in the Linking step. Template classes define how classes "should" be created, they're literally templates. During compile time g++ compiles each cpp file individually so the compiler sees your template on how to create a class but no instructions on what "classes" to create. Therefore ignores it. Later during the linking step the g++ attempts to link the file containing the class (the one that doesn't exist) and fails to find it ultimately returning an error.
To remedy this you actually need to "explicitly instantiate" the class by adding the following lines to Gene.cpp after the definition of the class
template class Gene<whatever_type_u_wanna_use_t>;int
Check out these docs I found them to be super helpful.