C++: Calling a templated function from main() [duplicate] - c++

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 9 years ago.
It's the first time that I try to use templates in my functions but I can't seem to make them work. I defined my function in a file called ddc.hpp
#ifndef __DIGITAL_DOWN_CONVERTER_H__
#define __DIGITAL_DOWN_CONVERTER_H__
namespace ddc {
template <class T> void perform_resampling(std::vector<T> &, unsigned int, unsigned int);
}
#endif
and implemented it in ddc.cpp
#include "ddc.hpp"
template <class T>
void ddc::perform_resampling(std::vector<T> &data, unsigned int f1, unsigned int f2) {
// do stuff
}
and here's my main.cpp
#include "ddc.hpp"
int main() {
std::vector<float> v (100000);
ddc::perform_resampling(v, 1000, 10);
return 0;
}
Compiling with gcc (linux) I get the following error:
$ g++ -c ddc.cpp -o ddc.o -Wall -O3 -lm -m64
$ g++ -c main.cpp -o main.o -Wall -O3 -lm -m64
$ g++ ddc.o main.o -o ../bin/resampler
main.o: In function `main':
main.cpp:(.text.startup+0xed): undefined reference to `void ddc::perform_resampling<float>(std::vector<float, std::allocator<float> >&, unsigned int, unsigned int)'
collect2: ld returned 1 exit status
make: *** [../bin/HW_3] Error 1
Am I doing something wrong?

Template definitions need to go with declarations, so everything needs to be in the header file.

You need to put your template implementation in the header too.

You need to place the definition of the template function in a location that is visible to the code that uses it or use explicit template instantiation to ensure the code for the function is generated.
If you do not want to expose the implemention of perform_resampling you can still force the the compiler to explicitly generate the code for it. The following line when placed in ddc.cpp will instruct the compiler to generate code for perform_resampling taking a vector<float> as it's first parameter.
template void ddc::perform_resampling(std::vector<float> &data, unsigned int f1, unsigned int f2);

Related

In C++, why must class member functions be defined outside class for separate compilation?

The following is a simple example for separate compilation:
// mod.cpp
#include <cstdio>
class MyModule {
public:
void print_msg();
};
void MyModule::print_msg() {
printf("hello from module\n");
}
// main.cpp
class MyModule {
public:
void print_msg();
};
int main() {
MyModule a;
a.print_msg();
}
We can compile and run it with
g++ main.cpp -c -o main.o
g++ mod.cpp -c -o mod.o
g++ main.o mod.o -o main
./main
The above works fine, but if I move the definition of MyModule::print_msg inside the class:
// mod.cpp
#include <cstdio>
class MyModule {
public:
void print_msg() { printf("hello from module\n"); }
};
I get an 'undefined reference' error for compiling main:
g++ main.cpp -c -o main.o # OK
g++ mod.cpp -c -o mod.o # OK
g++ main.o mod.o -o main # undefined reference error
/usr/bin/ld: main.o: in function `main':
main.cpp:(.text+0x23): undefined reference to `MyModule::print_msg()'
collect2: error: ld returned 1 exit status
I know that the former is the standard way and the class definition should go to a header file, but I wonder why the second method doesn't work.
Functions defined inside the class are implicitly inline. C++ requires:
The definition of an inline function [or variable (since C++17)] must be reachable in the translation unit where it is accessed.
Since you only defined it in mod.cpp, no definition is reachable in main.cpp, and compilation fails.
Typically, you'd put the definition of the class, and the definition of all functions defined within it, in a header file to be included by all users of the class. The functions defined outside the class then go in a .cpp file. That way a single consistent definition of all the inline functions is available to all users of the class, and you're not repeating the definition of the class in each .cpp file manually.

Separate inline class member function declaration and definition to different files (header and source)

I have 3 files: main.cpp, gp_frame.cpp and gp_frame.h. I wish to declare a class (named gp_frame) in gp_frame.h and define the member functions in gp_frame.cpp and want to use the class in main.cpp.
Broadly, the three files:
/*main.cpp*/
#include "gp_frame.h"
void plotpicture(unsigned int a, unsigned int b, unsigned int c, unsigned int d, unsigned int e){
anita.wait_enter("Some string\n");
}
int main(){
gp_frame anita(true);
plotpicture(1,2,3,4);
return 0;
}
/*gp_frame.h*/
class gp_frame{
public: void wait_enter(std::string uzi);
gp_frame();
gp_frame(bool isPersist);
};
/*gp_frame.cpp*/
#include "gp_frame.h"
void gp_frame::wait_enter(std::string uzi){
/*Some of code*/
}
gp_frame::gp_frame(){
/*Some of code*/
}
gp_frame::gp_frame(bool isPersist){
/*Some of code*/
}
Then, I want to compile and link the files:
g++ -c main.cpp -w -Wall
g++ -c gp_frame.cpp -w -Wall
g++ gp_frame.o main.o -o Myprogram
And everything is OK. However, if I want to declare/define function wait_enter as inline like:
/*in gp_frame.h*/
public: inline void wait_enter(std::string uzi);
/*in gp_frame.cpp*/
inline void gp_frame::wait_enter(std::string uzi){
/*Some of code*/
}
the compiler works as well, but the linker throws me an error:
main.o: In function `plotpicture(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int)':
main.cpp:(.text+0x2c6b): undefined reference to `gp_frame::wait_enter(std::string)'
collect2: error: ld returned 1 exit status
Can you explain me how to solve the problem or what do I wrong?
Sadly, neither extern inline nor static inline solves my problem.
what do I wrong?
You declare an inline function gp_frame::wait_enter(std::string), but you didn't define the function in all of the compilation units (source files) that use the function which is required by the standard.
In particular, you only defined the function in gp_frame.cpp but not in main.cpp, even though you do use the function in main.cpp.
how to solve the problem
Define inline functions in all compilation units that use them. The idiomatic way to do that is to define them in the same header that also declares them (gp_frame.h in this case).

Undefined reference to function from a different header file c++ [duplicate]

This question already has answers here:
Linking files in g++
(4 answers)
Why can templates only be implemented in the header file?
(17 answers)
Closed 8 years ago.
I am simply trying to use a function whose prototype is declared in a separate header file (ML_hash.h) and whose declaration is made in separate cpp file. I am trying to call this function in a different header file (HashNode.h). Here is the relevant code:
HashNode.h:
#ifndef HASHNODE_H
#define HASHNODE_H
#include "ML_hash.h"
template < typename T >
class HashNode
{
... // function prototype declarations
};
template< typename T >
void HashNode< T >::insert(int key, T* object)
{
...
int retVal = ML_hash(1, 3);
...
}
...
#endif
ML_hash.h:
#ifndef INC_ML_HASH
#define INC_ML_HASH
int ML_hash(int level, int key );
#endif
The error I am getting is:
g++ -o hash Hashtest.o:
Hashtest.o: In function `HashNode<int>::insert(int, int*)':
/home/adalal1/programs/class/final_project/HashNode.h:72: undefined reference to ' ML_hash(int, int)'
/home/adalal1/programs/class/final_project/HashNode.h:88: undefined reference to ` ML_hash(int, int)'
Hashtest.o: In function `HashNode<int>::explode()':
/home/adalal1/programs/class/final_project/HashNode.h:117: undefined reference to ` ML_hash(int, int)'
collect2: error: ld returned 1 exit status
What I don't understand is why the C++ compiler doesn't recognize the ML_hash function defined in ML_hash.cpp. I did include ML_hash.h in that cpp file. Could anyone provide insight into why this is happening?
EDIT:
I compile the code with a Makefile shown below:
C++ = g++
CFLAGS = -c -g
all: hash
hash: Hashtest.o
$(C++) -o hash Hashtest.o
clean:
rm -f *.o
%.o: %.cpp
$(C++) $(CFLAGS) $*.cpp
'ld returned 1 exit status' -> this is a linker error, not a compiler error.
Looks like you are running into this issue:
Linking files in g++
EDIT:
Either
g++ -o hash ML_hash.cpp HashNode.cpp HashTest.cpp
or
g++ -c ML_hash.cpp
g++ -c HashNode.cpp
g++ -c HashTest.cpp
g++ -o hash ML_hash.o HashNode.o HashTest.o
EDIT2 with OP edit:
I'm no makefile expert, but it looks like the 'hash:' target is just missing ML_hash.o and HashNode.cpp
hash: HashNode.o
ML_hash.o
Hashtest.o
$(C++) -o hash Hashtest.o ML_hash.o HashNode.o

undefined reference with member implelementation of a templated class

This is wholy mysterious to me. I'm using g++ on ubuntu, and this is some of my code (with class names change, but nothing else because I'm still using stubs everywhere):
Bob.hpp
template <class A>
class Bob : public Jack<Chris, A>
{
public:
Bob(int x1, int x2, float x3 = 1.0, float x4 = 2.0, float x5 = 3.0) throw(Exception);
virtual ~Bob();
};
I implemented in another file like this:
Bob.cpp
template <class A>
Bob<A>::Bob(int x1, int x2, float x3, float x4, float x5) throw(Exception)
{
}
template <class A>
Bob<A>::~Bob()
{
}
and I used it like this:
main.cpp
int main()
{
Bob<Alice> instance(1, 2);
}
Compiling with:
g++ -c Bob.cpp -o Bob.o
g++ -c main.cpp -o main.o
g++ -L"libs" -llib main.o Bob.o prog
gives me
main.o: In function main':
main.cpp:(.text+0x1fd): undefined reference toBob::Bob(int, int, float, float, float)'
collect2: ld returned 1 exit status
I am completely stumped. Changing the order with the g++ linking stage makes no difference. Compiling the object files generates no problems. And Why an undefined reference when I implemented the constructor? If anyone could shed any light on this, it's be much appreciated.
You need to move the code from Bob.cpp into Bob.hpp. When the compiler sees the definitions of Bob::Bob and Bob::~Bob in Bob.cpp, it does not know what types of Bob are actually going to be instantiated (i.e. Bob<int> vs Bob<SomeClass> and the code for them isn't generated.
Alternatively, you can still place the code in the Bob.cpp file, but you need to declare which types of Bob are going to be instantiated, e.g.:
Inside of Bob.cpp:
template
class Bob<Alice>;
The declarations and definitions of the class template member functions should all be in the same header file.
When compiling Bob.cpp, the compiler has both the declarations and the definitions available. At this point the compiler does not need to generate any definitions for template classes, since there are no instantiations. When the compiler compiles main.cpp, there is an instantiation: template class Bob<Alice>. At this point the compiler has the declarations but no definitions!
In addition to the issues raised by others, libraries must come last on the GCC command line. Instead of:
g++ -L"libs" -llib main.o Bob.o prog
you want:
g++ -L"libs" main.o Bob.o prog -llib
Where do you think the constructor of Bob<Alice> should be defined? It wasn't defined in Bob.cpp, because there was no mention of a Bob<Alice> in Bob.cpp. There was a template, which could have been used to define Bob<Alice> when Bob.cpp was compiled into Bob.o, but it wasn't.
Put the template definition in Bob.hpp, or Bob<Alice> in Bob.cpp.

c++ class with templates compilation error

I'm not an experienced C++ programmer and I'm having problems compiling. I've got a Heap class that uses a template:
template <class T>
class Heap
{
public:
Heap(const vector<T>& values);
private:
vector<T> d;
// etc.
};
And then in a separate implementation file:
template <class T>
Heap<T>::Heap(const vector<T>& values)
{
d = values;
for (unsigned int i = d.size()-1; i > 0; i--) Heapify(ParentIndex(i));
}
// ... more implementation code ...
And finally a main.cc file:
int main (int argc, char *argv[])
{
vector<int> in;
unsigned int i;
while (cin >> i) in.push_back(i);
Heap<int> h = Heap<int>(in);
return 0;
}
I get these compile errors:
g++ -Wall -I/opt/local/include -c -o main.o main.cc
g++ -Wall -I/opt/local/include -c -o heap.o heap.cc
g++ -Wall -o heap main.o heap.o
Undefined symbols:
"Heap<int>::Heap(std::vector<int, std::allocator<int> > const&)", referenced from:
_main in main.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
make: *** [heap] Error 1
Why does this not compile? I think the linker is saying it can't find the constructor, but I know it made the object file.
Templates need to be defined 100% within the header file. If you have your Heap<T> implementation in a .cc / .cpp file that is the problem. Move all of the code to the header file and it should fix your issue.
According to the C++ standard, you can use the export keyword thus:
export template<typename foo>...
However, most compilers don't support this. The C++ FAQ has some more info: http://www.parashift.com/c++-faq-lite/templates.html#faq-35.14
See JaredPar's answer for something that's actually reliable.