undefined reference with member implelementation of a templated class - c++

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.

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.

Clang++ makes linker fail on template classes (but it works with g++)

I have a program that works nicely with GCC, but compiling it with Clang instead makes the linker fail.
I think my issue is with template classes, so I implemented this small example.
test.cpp:
#include "Point.h"
int main()
{
Point<int> p1;
Point<int> p2{ 3, 6 };
}
Point.h:
#ifndef POINT_H
#define POINT_H
template<typename T>
class Point {
T x, y;
public:
Point();
Point(T, T);
};
template class Point<int>;
template class Point<float>;
#endif
Point.cpp:
#include "Point.h"
template<typename T>
Point<T>::Point()
: x{0}, y{0}
{}
template<typename T>
Point<T>::Point(T t_x, T t_y)
: x{t_x}, y{t_y}
{}
When I build it with g++ Point.cpp test.cpp, it works without a problem.
But with Clang, it gives the following errors:
$ clang++ Point.cpp test.cpp
/usr/bin/ld: /tmp/test-8ab886.o: in function `main':
test.cpp:(.text+0x1a): undefined reference to `Point<int>::Point()'
/usr/bin/ld: test.cpp:(.text+0x2d): undefined reference to `Point<int>::Point(int, int)'
clang-11: error: linker command failed with exit code 1 (use -v to see invocation)
Or, using lld:
$ clang++ -fuse-ld=lld Point.cpp test.cpp
ld.lld: error: undefined symbol: Point<int>::Point()
>>> referenced by test.cpp
>>> /tmp/test-f95759.o:(main)
ld.lld: error: undefined symbol: Point<int>::Point(int, int)
>>> referenced by test.cpp
>>> /tmp/test-f95759.o:(main)
clang-11: error: linker command failed with exit code 1 (use -v to see invocation)
I guess my explicit instantiations in Point.h aren't good enough for Clang, but I can't figure what it wants.
Your explicit instantiation should be where definitions are visible, so at the end of Points.cpp
From class_template#Explicit_instantiation:
An explicit instantiation definition forces instantiation of the class, struct, or union they refer to. It may appear in the program anywhere after the template definition, and for a given argument-list, is only allowed to appear once in the entire program, no diagnostic required.

g++ removes useless function? Undefined reference

I have hpp file with declaration:
namespace X {
class Y {
public:
[other functions]
inline float basicFunction();
int someFunction();
[other functions]
};
}
And in cpp file:
namespace X {
[implementations etc.]
inline float Y::basicFunction() {
return someValue * someMath / moreMath;
}
int Y::someFunction() {
return basicFunction() * 100;
}
[other functions]
}
I'm using it at other cpp file, but I think this isn't problem. Compiling with:
g++ -c someclass.cpp -o someclass.o -std=c++11
g++ -c main.cpp -o main.o -std=c++11
g++ main.o someclass.o -o main -std=c++11 -O0
Throw error:
main.o: In function `main':
main.cpp:(.text+0x4d9): undefined reference to `X::Y::someFunction()'
Why? How I can compile it correct?
I know that someFunction() is useless, but this is called many times and I just like that way.
All code above isn't real, so may have bugs, but on my program it's (I think) correct
I tried many combinations (both functions with same return type, both inline, none inline etc.) and no effect.
Solved. Function cannot be inline.
Still don't know why it worked after some attempts after deleted inline but nevermind.
Explanation why function in this code can't be inline is simple. Compiler, when see "inline", don't create pointer to function, but paste code in the place of reference.
Just my mistake...

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

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);

template specialization in another file c++. Which version gets

I have these files :-
1.h :-
#include <iostream>
using namespace std;
template <typename A>
void f() {
cout<<"generic\n";
}
1.cpp :-
#include "1.h"
template <>
void f<int> () {
cout<<"for ints only\n";
}
main.cpp :-
#include "1.h"
int main() {
f<int>();
return 0;
}
Now, I compile and run these with g++ like this :-
g++ -c 1.cpp -o 1.o
g++ main.cpp 1.o
./a.out
And I get :-
for ints only
On the other hand, I compile it with icpc like this :-
icpc -c 1.cpp -o 1.o
icpc main.cpp 1.o
./a.out
And I get :-
generic
What does the C++ standard say about this? Is any one compiler "right" and the other "wrong" or is the standard ambiguous on this issue and both are "right" ?
Your program exhibits undefined behavior. The specialization must be declared in every translation unit in which it is used, per C++11 ยง14.7.3/6:
If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required.