A strange 'undefined reference to' error with g++ [duplicate] - c++

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
"undefined reference" to a template class function
(4 answers)
Closed 9 years ago.
See my demo code below:
b.hpp:
#ifndef B_HPP
#define B_HPP
namespace debug {
class test {
public:
template <class T> void foo(T a);
private:
int a;
};
}
#endif
b.cpp:
#include <iostream>
#include "b.hpp"
namespace debug {
template <class T>
void test::foo(T a) {
std::cout << "debug" << std::endl;
}
}
testb.cpp:
include "b.hpp"
int main(int agrc, char *argv[])
{
debug::test a;
int c = 5;
a.foo(c);
return 0;
}
I compile it with
g++ -std=c++11 testb.cpp b.cpp'
and get a error:
/tmp/ccnjR5S4.o: In function `main':
testb.cpp:(.text+0x1c): undefined reference to `void debug::test::foo<int>(int)'
collect2: error: ld returned 1 exit status
What's the problem?
If I put main function in b.cpp and compile b.cpp, it 's ok. Why?
Thanks!

This is one of the cases where you need explicit instantiation, or to move code back into b.hpp. This arises because the implementation of debug::test::foo isn't visible when you compile testb.cpp, and the compiler has no way of knowing what might be needed when it compiles b.cpp.
To explicitly instantiate debug::test::foo<int>, add the following line to b.cpp:
#include <iostream>
#include "b.hpp"
namespace debug {
template <class T>
void test::foo(T a) {
std::cout << "debug" << std::endl;
}
// Explicitly instantiate test::foo<int>
template void test::foo<int>(int); // <-- add this line
}
Alternately, if you do not know all the ways this template might get instantiated, move its definition back into the class definition in the header. Ugly, but it'll work.
Some compilers do cross-compilation unit template instantiation, but as you've discovered, g++ isn't one of them. (At least, not as it's configured on my system.)
Edit: As #juanchopanza pointed out above, this thread gives a good explanation of what's going on: Why can templates only be implemented in the header file?

Related

C++ class template undefined reference to function [duplicate]

This question already has answers here:
undefined reference to template function [duplicate]
(2 answers)
Closed 6 years ago.
I keep getting undefined reference when i call the two functions from my template class "add" and "greater" in my main function.
So, i have:
number.h
#ifndef NUMBER_H
#define NUMBER_H
template <class T>
class number {
public:
T x;
T y;
number (int a, int b){
x=a; y=b;}
int add (T&);
T greater ();
};
#endif
number.cpp
#include "number.h"
template <class T>
int number<T>::add (T& rezAdd){
rezAdd = x+y;
return 1;
}
template <class T>
T number<T>::greater (){
return x>y? x : y;
}
And my main file is: resolver.cpp
#include <stdio.h>
#include <stdlib.h>
#include "number.h"
int main (int argc, char **argv) {
int aux;
number<int> c(3,5);
c.add(aux);
printf ("number added [%d]\n", c.add(aux));
printf ("greater number: [%d]\n", c.greater());
return 0;
}
The errors that i keep getting are:
g++ -Wall -o tema1 resolver.cpp number.cpp
/tmp/ccX483J4.o: In function `main':
resolver.cpp:(.text+0x34): undefined reference to `number<int>::add(int&)'
resolver.cpp:(.text+0x47): undefined reference to `number<int>::add(int&)'
resolver.cpp:(.text+0x64): undefined reference to `number<int>::greater()'
collect2: ld returned 1 exit status
make: *** [all] Error 1
Thanks for the help in advance!
I prefer to have all of my functions in the .cpp file, regardless of whether they are template functions or regular functions. And there is a way to do that with some basic #ifndef magic. Here's what you can do:
main.cpp
#include "myclass.hpp"
int main()
{
// ...
}
myclass.hpp
#ifndef MYCLASS
#define MYCLASS
template<class T>
class MyClass
{
T val;
public:
MyClass(T val_);
}
#define MYCLASS_FUNCTIONS
#include "myclass.cpp"
#endif
myclass.cpp
#ifndef MYCLASS_FUNCTIONS
#include "myclass.hpp"
// regular functions:
// ...
#else
// template functions:
template<class T>
MyClass<T>::MyClass(T val_)
:val(val_)
{}
// ...
#endif
Here's how the precompiler sees it. We have two .cpp files.
When we compile main.cpp we:
include myclass.hpp
check that MYCLASS is undefined, and it is
define it
give compiler the definitions of the generated class (from template class)
include myclass.cpp
define MYCLASS_FUNCTIONS
check if MYCLASS_FUNCTIONS is defined, it is
give compiler the definitions of the generated functions (from template functions)
When we compile myclass.cpp
check if MYCLASS_FUNCTIONS is defined, it isn't
include myclass.hpp
check that MYCLASS is undefined, and it is
define it
give compiler the definitions of the class
include myclass.cpp
include myclass.hpp again
this time MYCLASS is defined so do nothing inside, return to myclass.cpp
check if MYCLASS_FUNCTIONS is defined, it is
give compiler the definition of the generated functions (from template functions)
exit include twice
pass to the compiler all the regular functions
Your class is named wrong. Your class is named cai where all your functions belong to a class named number: http://ideone.com/ZayX0c
One more thing.. you cannot have templates in the .cpp file. Template functions/defintions go in the header along with the class declaration. This is the reason for your undefined function error. Non-template functions go in the .cpp.
#include <cstdio>
#include <cstdlib>
template <class T>
class number {
public:
T x;
T y;
number (int a, int b){
x=a; y=b;}
int add (T&);
T greater ();
};
template <class T>
int number<T>::add (T& rezAdd){
rezAdd = x+y;
return 1;
}
template <class T>
T number<T>::greater (){
return x>y? x : y;
}
int main (int argc, char **argv) {
int aux;
number<int> c(3,5);
c.add(aux);
printf ("number added [%d]\n", c.add(aux));
printf ("greater number: [%d]\n", c.greater());
return 0;
}
Move the definitions of the add and greater function templates into your number.h.
Remember that add and greater aren't functions, they're function templates. To create actual functions, the compiler has to instantiate the template for specific types, such as int, and it can only do that if it has access to the template's definition at the point where it discovers that an instance is needed.
When you compile number.cpp, the compiler has access to the templates' definitions, but it doesn't see any code that requires a specific instance (such as number<int>), so it doesn't generate instances.
When you compile resolver.cpp, the compiler sees that it needs to instantiate those templates for the int type, but it can't since it doesn't have their definitions. So it generates "external references", basically notes telling the linker to look for those functions in some other object file.
The result is that the function templates don't get instantiated in either object file — in one because the compiler didn't know that it should, and in the other because it couldn't — so when the linker goes looking for them (to resolve those external references), it can't find them. That's why you get the error.
Moving the template function definitions into the header makes them visible to the compiler while it's compiling main.cpp, so it's able to instantiate those functions for the int type. Function templates typically need to be defined in header files, rather than .cpp files, for exactly this reason.

compile header files defines a template class which also includes other header files [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
JUST to make it clear : it is different from the problem that we must define functions of template class in the header file.
UPDATE : if you need the real source code, you can download it here : https://Near#bitbucket.org/Near/compile_error.git
I implement a double list class.
// list.h //
class list {
//...
void insert(...);
};
// list.cpp //
#include "list.h"
void list::insert(...) {
...
}
I also implement a template class which include the list.h
// template_class.h //
#include "list.h"
template<class T>
class temp_class {
list l;
void func();
}
void temp_class::func() {
//...
l.insert(...);
}
Now I write a test.cpp file which include the template_class.h and call the func function
// test.cpp //
#include "template_class.h"
int main() {
temp_class<int> t;
t.func();
return 0;
}
I compile like this
g++ test.cpp list.cpp -o test
The compiler complains that test.cpp : "undefined reference to insert".
Why can't it work? How to solve this error?
FYI : If I include the content in list.cpp in list.h and just compile test.cpp, it works. But I don't think it is a good idea.
When compiling your code I immediately get the warning:
list_double.h:14:15: warning: inline function ‘void list_double_node::list_double_insert_first(list_double_node*)’ used but never defined [enabled by default]
void inline list_double_insert_first(list_double_node* entry);
That is, your code is actually akin to this SSCCE:
// list.h
class list {
public:
inline void insert(int);
};
.
// list.cpp
#include "list.h"
void list::insert(int) {
}
.
// template_class.h
#include "list.h"
template<class T>
class temp_class {
list l;
public:
void func();
};
template <class T>
void temp_class<T>::func() {
l.insert(17);
}
.
// test.cpp
#include "template_class.h"
int main() {
temp_class<int> t;
t.func();
return 0;
}
The fix is: either remove the inline or define the function in the header. The rules for inline are actually pretty much the same as those for template: whenever an inline function is used, its implementation has to be provided.

Use arbitrary functions as template parameter arguments

I have an Apache module (.so) that contains a class I'm trying to completely decouple from Apache itself. The biggest source of frustration is the debug logging. I want to be able to pass the logging function to the class through the template parameters. I can get the proof of concept to work fine when everything is in the same translation unit, but it falls over once they're not because the logging function is an 'undefined reference':
/tmp/ccPdPX2A.o: In function `main':
test.cpp:(.text+0x81): undefined reference to `void C::DoThis<&(LogIt(char const*, ...))>()'
collect2: ld returned 1 exit status
This also happens when Apache tries to load the module containing the class.
The code below reproduces the problem:
// main.cpp
#include <iostream>
#include "C.h"
void LogIt(const char*, ...)
{
std::cout << "GADZOOKS!\n";
}
int main(int argc, char* argv[])
{
C c;
c.DoThis<LogIt>();
}
// C.h
typedef void (*LogFunction)(const char*, ...);
class C
{
public:
template <LogFunction L>
void DoThis();
template <LogFunction L>
void DoThat();
};
// C.cpp
#include "C.h"
template <LogFunction L>
void C::DoThis()
{
L("DoThis!");
DoThat<L>();
}
template <LogFunction L>
void C::DoThat()
{
L("DoThat!");
}
I'd prefer not to have to resort to having the function passed as a function parameter, i.e.
template <typename F>
void C::DoThis(F f)
{
f("DoThis!");
}
because I'd like to structure the code in such a way that the compiler is able to figure out if the body of LogIt is empty (which it will be for Release builds) and not generate any code for the call, and I'd have to pass it as an argument everywhere in the class.
Can it be done?
Okay I recreated everything,
This error undefined reference to void C::DoThis<&(LogIt(char const*, ...))>() is explained here
Now if you do #include "C.cpp" referring above, this will lead to
undefined reference to void C::DoThat<&(LogIt(char const*, ...))>()
So fix:
template <LogFunction L>
void C::DoThat() //Notice :: used here
{
L("DoThat!");
}
and everything complies and execute !
This is because you have your templates invisible at the point where compiler is supposed to instantiate them as you only have a declaration in C.h and a definition in C.c.
Either move template definitions to header or force instantiation in C.c. You will have to provide LogIt declaration in C.c for that.
You need to put template definition in the same as the place where its declared. So that means you need to put your LogIt function where it was declared in the header file. As of right now, we are not able to explicitly separate template declaration and its definition like that.

What is a robust way of template specialization in C++ for separated header/source

In moderate-sized or even big complex projects separating template declaration and definition is useful
to reduce compilation time.
However, in a complex code small programmer mistakes may lead to unnoticed behaviour change,
e.g. a generic version is called instead of a specialization.
Example:
Template specialization became invisible due to a missed declaration.
///////////////////// file A.hpp /////////////////////
#include <iostream>
template <typename T>
class A
{
public:
void foo()
{
std::cerr << " calling generic foo " << std::endl ;
}
};
// forgetting following declaration leads to an unintended program behaviour
template <> void A< int >::foo();
///////////////////// file A-foo-int.cpp /////////////////////
#include "A.hpp"
template <>
void A< int >::foo()
{
std::cerr << "calling <int> version of foo" << std::endl;
}
///////////////////// file main.cpp /////////////////////
#include "A.hpp"
int main(int argc , char** argv)
{
A<int>* a = new A<int>();
a->foo();
return 0;
}
///////////////////// Makefile /////////////////////
CC = g++
CPPFLAGS += -Wall -O3
CXXFLAGS += --std=gnu++0x
all: nonrobust-template-setup
nonrobust-template-setup: main.o A-foo-int.o
$(CC) $(CPPFLAGS) main.o A-foo-int.o -o nonrobust-template-setup
clean:
rm -rf *.o nonrobust-template-setup
//////////////////////////////////////////
Question:
is a more robust setup possible (compiler- and platform-independent)
and if, how would it look like?
If not, what is a good way to test that a desired function version is called?
You cannot separate declarations and definitions that way: if you relegate the definition of your specialized member functions in a separate .cpp file, no matter if you declare your specialization immediately after the primary template, the compiler won't be able to instantiate it, and the linker will complain about unresolved references.
Normally, the definition of member functions of a class template goes in a header file, unless you provide an explicit instantiation for the corresponding class templates:
template class X<int>; // You should add this to make your program build,
// or instantiate the corresponding class template
// specialization and invoke the foo() method in the
// same translation unit (A.cpp)
In general, unless you are facing really horrible compilation time issues, I would suggest you to follow the common practice and put everything in a header file to be included by all the translation units that need to use the class template:
///////////////////// file A.hpp /////////////////////
#include <iostream>
template <typename T>
class A
{
public:
void foo()
{
std::cerr << "error: called generic foo " << std::endl ;
}
};
template <>
void A< int >::foo()
{
std::cerr << "calling <int> version of foo" << std::endl;
}
///////////////////// file main.cpp /////////////////////
#include "A.hpp"
int main(int argc , char** argv)
{
A<int>* a = new A<int>();
a->foo();
return 0;
}
If you are facing really horrible compilation time issues, then you could separate the member function definitions and put them into separate translation units with explicit instantiations, but in C++11 there is no clean/easy way to make sure that all the specializations you relegate in separate .cpp files are declared immediately after the primary template (as good practice recommends). If there were, I guess it would be so popular that you wouldn't have needed to come here and ask about it, because everybody faces such a design issue.
In some cases some fancy macros could help, but doubtfully they would bring more benefit than maintenance pain in really complex projects.
A solution to this problem was attempted in the C++03 standard by introducing the export keyword, but implementation experience proved it too hard to support for compiler vendors, which is why export is no more part of the C++ Standard (since C++11).
Hopefully, a better solution for modules will make it into C++14 and provide a solution for template design.
I think the best you can do is to static_assert that the generic template is never instantiated with the types that are supposed to be specialized.
The following code is to illustrate only - I'd probably use BOOST_STATIC_ASSERT (and std::is_same if I could use c++11). The basic idea is to prevent implicitly instantiating the non-specialized template with the set of types you forbid. Of course if you forget to add the static assert AND the specialization you're still going to fail.
template<class T, class U>
struct is_same { enum { value = false }; };
template<class T>
struct is_same<T, T> { enum { value = true }; };
template <bool enable>
struct StaticAsserter
{
char test[enable];
};
template <typename T>
struct foo
{
// Make sure we can't implicit instantiate foo for int.
StaticAsserter<!is_same<int, T>::value> DisallowInt;
};
int main()
{
foo<unsigned> hi;
foo<int> fail;
return 0;
}
The way to be sure of this is to not provide any definition of the generic template's foo(). There's no need to declare specializations when you're doing it this way:
// A.h
template <typename T> struct A { void foo(); };
// main.cc
#include "A.h"
int main ( int c, char **v )
{
A<int>().foo();
// A<long>().foo(); // this line will compile but not link
}
// A.cc
#include <cstdio>
#include "A.h"
template<> void A<int>::foo() { puts("foo!"); }
Okay, from comments instantiating the generic A<T>::foo() implementation is not necessarily an error, only if you have supplied a specialization elsewhere.
So what you want is to find generic-template instantiations whose names duplicate specializations that should only have been instantiated in a specific list of compiler object files -- which reduces to looking for matching fields in two datasets. For that, there's join:
# every object and where it's defined
nm -A *.o | c++filt | grep ' T ' \
| sort -k3 > #all.definitions
# definitions that shouldn't be duplicated:
nm -A A-foo-int.o | c++filt | grep ' T ' \
| sort -k3 > #my.definitions
# everything that shows on both lists:
join -j3 #my.definitions #all.definitions
edit: sed syntax for the grep patterns didn't really work very well.

Understanding template classes in c++ - problem with new-operator

Dear all, I've been stuck with this problem now for a few days and my searches were not successful.
What I am trying to do:
I want a template reader class (VariableReader) to handle different types of variables (usually unsigned int and pointers to vector).
I started with
#ifndef READER_H_
#define READER_H_
#include <string>
namespace BAT {
template <typename variableType = unsigned int>
class VariableReader {
public:
VariableReader<variableType>();
VariableReader<variableType>(std::string varName);
virtual ~VariableReader<variableType>();
std::string getVariableName();
void setVariableName(std::string varName);
bool isValidVariableName(std::string varName);
variableType getVariable();
private:
std::string variableName;
variableType variable;
};
}
#endif
and
#include "../../interface/Readers/VariableReader.h"
namespace BAT {
template<typename variableType>
VariableReader<variableType>::VariableReader() :
variableName("") {
// TODO Auto-generated constructor stub
}
template <typename variableType>
VariableReader<variableType>::VariableReader(std::string varName) :
variableName(varName) {
}
template <typename variableType>
std::string VariableReader<variableType>::getVariableName() {
return variableName;
}
template <typename variableType>
void VariableReader<variableType>::setVariableName(std::string varName) {
if (VariableReader::isValidVariableName(varName)) {
variableName = varName;
}
}
template <typename variableType>
bool VariableReader<variableType>::isValidVariableName(std::string varName) {
return varName != "";
}
template <typename variableType>
VariableReader<variableType>::~VariableReader() {
// TODO Auto-generated destructor stub
}
}
However, although it seems to compile I can't use it within other projects.
EDIT: forgot to post test-code:
#include "cute.h"
#include "ide_listener.h"
#include "cute_runner.h"
#include "Readers/VariableReader.h"
using namespace BAT;
static VariableReader<int> *reader;
void setUp(){
reader = new VariableReader<int>::VariableReader();//this is problem-line
}
void thisIsATest() {
ASSERTM("start writing tests", false);
}
void runSuite(){
cute::suite s;
//TODO add your test here
s.push_back(CUTE(thisIsATest));
cute::ide_listener lis;
cute::makeRunner(lis)(s, "The Suite");
}
int main(){
runSuite();
}
I get following error message:
Building target: BAT_Tests
Invoking: GCC C++ Linker
g++ -L"/workspace/BAT/Debug Gcov" -fprofile-arcs -ftest-coverage -std=c99 -o"BAT_Tests" ./src/Test.o -lBAT
./src/Test.o: In function `setUp()':
/workspace/BAT_Tests/Debug Gcov/../src/Test.cpp:13: undefined reference to `BAT::VariableReader<int>::VariableReader()'
collect2: ld returned 1 exit status
make: *** [BAT_Tests] Error 1
As I understand it the linker tries to find the constructor for VariableReader, which is not explicitly defined since I want to have a general constructor only.
Please help me to understand what I am missing.
The C++ FAQ Lite section on How can I avoid linker errors with my template functions? shows two solutions:
Move the template class's methods into the .h file (or a file included by the .h file).
Instantiate the template in the .cpp file using template VariableReader<unsigned int>;.
The constructor(s) and destructor doesn't need the template arguments in it. In addition, template classes must have the full source available to compile- you can't declare the members and define them in another translation unit like you can with normal classes.