I am trying to compile a minimal example which instantiates
a template class. The example compiles fine when a certain order
of declarations is kept, but fails otherwise.
temp.h:
#include <iostream>
template <bool display>
class test {
public:
void sayHi();
};
temp.cpp:
#include "temp.h"
template <bool display>
void test<display>::sayHi () {
if (display) std::cout << "Hi";
}
main.cpp:
#include <iostream>
#include "temp.h"
int main () {
test<true> myobject;
myobject.sayHi();
return 0;
}
This is the standard of how to include classes.
In GCC 4.4.6, this fails with the error
main.cpp:(.text+0x3a): undefined reference to `test::sayHi()'
However, the example compiles when I do a #include "temp.cpp" instead of #include "temp.h" in main.cpp
file, so that the compiler reads the class declaration in temp.h first, then
sees the content of temp.cpp and only afterwards the content of main.cpp.
When I use non-template classes, it works fine to include just .h files
in main.cpp -- what is going wrong here? Note that the temp.cpp is included
in my Makefile, so it definitely should not be forgotten by the compiler.
Thanks for any help.
See the C++ FAQ Lite entry [35.12] Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?.
The definition (aka body) of the sayHi() method must be in the temp.h header, or in another included file; the full code is needed when you instantiate test<true>.
With templates, both declaration and definition must be in the same file. You can do this by either putting all your code in one file (and making the function definitions inline or not, it's up to you), or making the declaration and definitions seperate, but including the definitions file at the bottom of the .h file.
So it would be
tmp.h:
#include <iostream>
template <bool display>
class test {
public:
void sayHi();
};
#include "tmp.cpp"
and tmp.cpp and main.cpp remain the same (but you don't give tmp.cpp to the compiler to compile since it's included by tmp.h).
Many people name the files that have template function definitions in them with a .template extension instead of .cpp extension (it lets you know it's not to be compiled, plus it looks less weird than including a .cpp file), but you don't have to.
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.
I'm getting a redefinition error for every method in the class. I tried to put the .cpp code in the header where the "include Algebra.cpp" is, but didn't change a thing.
// This is the .h file
#ifndef ALGEBRA_H
#define ALGEBRA_H
#include <iostream>
template <size_t rows, size_t cols>
class Matrix {
double** matrix;
void debug_print();
public:
Matrix();
Matrix(double (&_matrix)[rows][cols]);
~Matrix();
double calculate_determinant();
};
#include "Algebra.cpp"
#endif
// This is the .cpp file
#include "Algebra.h"
#include <cassert>
template <size_t rows, size_t cols>
Matrix<rows, cols>::Matrix() {...}
// I have defined all the methods below..
First, that template function definition belongs in the header file that gets pulled in wherever it's needed with #include "algebra.h".
The reason you're getting problems with this particular setup is that, as several comments have suggested, you're compiling the .cpp file that contains that template function definition. When the compiler compiles "algebra.cpp", it first sees the #include directive at the top of the file, and pulls in the text from "algebra.h". That's fine as far as it goes, but at the end of "algebra.h" it sees #include "algebra.cpp". So it pulls in the text from there.
Now it's compiling "algebra.cpp" inside of "algebra.cpp". The include guard in "algebra.h" works here, so there is no redefinition of the contents of "algebra.h". And then it sees the definition of Matrix<rows, cols>::Matrix(). Still okay, so far.
Now it comes to the end of the code that comes in through the #include directive, so it continues to compile the code in "algebra.cpp", and it again sees the definition of Matrix<rows, cols>::Matrix(), and that's the redefinition that the compiler is complaining about.
That's why you shouldn't do that.
Some folks like to put definitions of member functions of class templates in a separate file from the header that defines the class template. That's okay, but don't compile that file; it should only be compiled as part of the header that uses it. And as a practical matter, that means giving it an extension that makes it clear that it's not a source file to be compiled on its own. When I've used that approach, I use ".inl" as the extension. If you change the name of "algebra.cpp" to "algebra.inl" and make sure that you're not telling the compiler to compile "algebra.inl" this problem should go away.
Consider the following code:
In header.h
#pragma once
class someClass
{
public:
void foo();
};
In header.cpp
#include "header.h"
inline void someClass::foo(){}
In main.cpp
#include <iostream>
#include "header.h"
using namespace std;
int main()
{
someClass obj;
obj.foo();
}
Here I get a link error because foo function is defined as inline in header.cpp, if I remove the 'inline' keyword, the compile and run will proceed without errors.
Please tell me why I get link error on this 'inline' function?
The way you wrote it, inline applies to the current file scope. When an inline function is in a header, that header is included in a cpp file, and then the function is inlined where it is used in that file's scope, so there is no problem. In this case, your function is available as inline only where it is defined, and no other cpp file sees it, except as a regular member declaration in its class, hence the link error.
If you want it to be inline, add the code and the inline keyword in the header.
I have a function that is the same across all my header files and main.cpp if I define it in main.cpp will they all be able to use it once they are included or will they have a compiler issue?
Still new to this whole header file business. Thanks in advance.
In the header file (myfunction.h), you need to have only declaration of the function:
int foo(int param);
In the main.cpp (or any other cpp file - better choice would be myfunction.cpp - just make sure definition is included in exactly one file!) file, you need to have definition of the function:
int foo(int param)
{
return 1;
}
In all other source (cpp) files where you're using function foo, just include myfunction.h and use function:
#include "myfunction.h"
void someotherfunction()
{
std::cout << foo(1) << std::endl;
}
Compiler only needs to see declaration of the function before it is used. Linker will connect definition of the function with the places you've used the function. If you forget to write definition in main.cpp file, you will not get compiler, but a linker error. It may be worth of mentioning that compiler is compiling each cpp file separately, and linker's job is to combine all compiler object files and to produce final output file. On most setups, linker will be called automatically after compiling, so you may not be familiar with it.
If you include entire function definition in the header file, that definition will be compiled in each translation unit where header file is included, and you will get multiple symbol definition linker error, or something similar - that's why you need to include only declaration of the function inside header file. However, there are exceptions for this - for example, you may declare your function inline - other answers explain this approach.
So, now myfunction.h contains the function declaration:
#ifndef MY_FUNCTION_H
#define MY_FUNCITON_H
// declaration
int myfunction();
#end if
myfunction.cpp contains the function definition:
int myfunction()
{
return 4;
}
Now, in file1.cpp and in file2.cpp you want to use this function, so you're including myfunction.h:
// file1.cpp
#include "myfunction.h"
// somewhere in the file
void foo()
{
std::cout << myfunction();
}
... and in the second file:
// file2.cpp
#include "myfunction.h"
// somewhere in the file
void bar()
{
/// ...
std::cout << myfunction();
}
Header files in C and C++ are a language artifact. They are the consequence of the fact, that C and C++ can be implemented as a single-pass compiler. In contrast, Pascal - for example - has a two-pass compiler, that skips over unknown entities during the first pass, and fills in the missing bits in a second pass. Consequently, in C and C++ every type, object, and method must be declared before it can be used. This is the main responsibility of header files.
Header files are expanded into any file that includes them. In other words: The preprocessor replaces the statement #include "foo.h" with the contents of the file "foo.h". With this being the case you need to be careful to not violate the single definition rule: An entity must not be defined more than once.
To meet both requirements you have two options: Declare and define the function in the header, using the inline keyword, or declaring it in the header only, and defining it in another compilation unit.
The following code illustrates both solutions:
// foo.h
inline void foo() {
// Method is implemented in this header file.
// It is marked 'inline' to prevent linker errors
// concerning multiply defined symbols.
...
}
Delaration in header only, implementation in another compilation unit:
// foo.h
extern void foo();
// foo.cpp (or another compilation unit)
void foo() {
...
}
Regardless of which solution you go with, you can use foo() from any compilation unit. If you want to use it from "main.cpp" the code would look something like this:
// main.cpp
#include "foo.h"
int main() {
foo();
}
So you have a function which is used in all your header files, why don't you make a utility.h which keeps track of these types of functions and inline the functions in the .h ?
Declare the function prototype in a custom header file:
int add(int a, int b);
let say header file name is myfunction.h and include it wherever you need the function.
now you can define a function on another.cpp or main.cpp
int add(int a, int b){
return a+b;
}
include your custom header file like this:
#include "myfunction.h"
remember your main.cpp and other cpp files and the new header file should be in the same path.
If you have two files:
main.cpp
#include "func.h"
int main(){
hello();
std::cout<<" world!\n";
return 0;
}
& func.h
#ifndef FUNC_H
#define FUNC_H
#include <iostream>
void hello(void){
std::cout<<"hello";
}
#endif
iostreams objects and functions e.t.c will work fine from within main.cpp.
This posts answers sum up #ifndef pretty well if you would like to know more.
Consider this code
#include <iostream>
#include <cstdio>
using namespace std;
class Dummy {
public:
Dummy();
};
inline Dummy::Dummy() {
printf("Wow! :Dummy rocks\n");
}
int main() {
Dummy d;
}
All is good here!
Now I do this modification. I move the declaration of Dummy to "dummy.h".
class Dummy {
public:
Dummy();
};
And define the constructor Dummy() as following in "dummy.cpp"
#include "dummy.h"
inline Dummy::Dummy() {
printf("Wow! :Dummy rocks\n");
}
And finally, I have my main file as:
#include <iostream>
#include <cstdio>
#include "dummy.h"
using namespace std;
int main() {
Dummy d;
}
It compiles fine, but I get a linker error complaining an undefined reference to Dummy::Dummy().
Any insights.
--
You have to put all inline functions (including methods and constructors/destructors) in a header file, where they are declared.
Though this code should work either way, with main() calling the constructor as if the inline keyword was not there. Are you sure you are passing object files from both compilation units to the linker?
You should think how compiling works at C++ and the idea of separate compiling units used at C++ and encapsulation gained using headers and cpp files.
Look here:
http://www.parashift.com/c++-faq-lite/inline-functions.html#faq-9.6
The inline tells the complier that instead of calling the function to "copy - paste" its code at the place of the function call. When you put the inline definition in a CPP file it won't be visible during linking to other compiled units (its in cpp file not in h file) so the compiler understand from the signature placed at the class that there is no-paramter Con's so it won't implement the default one. But the linker can't find the function body cause it is implemnted inline at the cpp file.
Try removing the inline specifier from the your implementation file. If my understanding is correct, you can only inline in a header