templates - undefined reference error - c++

I have the following simple template code:
#ifndef CLUSTER_H
#define CLUSTER_H
#include <iostream>
#include <vector>
template <typename T, size_t K>
class Cluster
{
public:
void Print() const;
private:
std::vector<T> objects;
};
template <typename T, size_t K>
void Cluster<T,K>::Print() const
{
for (int i=0; i<objects.size(); i++)
{
T curr=objects[i];
std::cout << curr << " ";
}
std::cout << std::endl;
}
#endif
and for some reason I get the following error: "undefined reference to 'Cluster<int, 5u>::Print() const'. What could be the cause for this?
Thanks!

So, I'm going to go out on a limb here and say that you've defined a template function in a CPP file, which means it will end up in a different translation unit. Here's a simple example:
A header, example.h
#ifndef EXAMPLE_H
#define EXAMPLE_H
template<int TValue>
class example
{
public:
int get_tvalue();
};
#endif
A source file, example.cpp
#include "example.h"
template<int TValue>
int example<TValue>::get_tvalue()
{
return TValue;
}
And another source file, main.cpp
#include "example.h"
int main()
{
example<5> instance;
instance.get_tvalue();
return 0;
}
If I compile these together using GCC, I get undefined reference to 'example<5>::get_tvalue()'. This is because of the way template classes are instantiated. A template class definition is just that... a template, not an actual class. The actual class definition is created when a parameterised (or specifically, fully specialised) definition of that class occurs, in this case, example<5>. That fully specialised class definition only exists in main.cpp... there's no such class inside example.cpp! Example.cpp contains only the template, and no specialisations. This means the function, get_tvalue is not defined for example<5> in main.cpp, hence the error.
You can fix this in one of two ways. The first way is to always have your entire template class defined in its header file. This is the way its done with STL containers, for example. The alternative is to force creation of a parameterised class in example.cpp... you can do this by adding
template class example<5>;
to the end of example.cpp. Because there's now an actual class definition for example<5> in example.cpp, you will also get an actual function definition for example<5>::get_tvalue and when your translation units main.o and example.o are linked together at the end of the compilation step everything will be fine.
Obviously, this would be a poor approach in most cases, but under circumstances where your template parameters take only a small range of values it can work. Putting your whole class in the header file is probably easiest, safest and most flexible though.

Related

Template specialisation in one TU hidden by another TU

I have a class template which can be specialised in order to change behaviour of a utility function for user defined types.
I have one translation unit which uses the utility function with my type's specialisation available. The specialisation is used.
In a separate translation unit, if I call the utility function without including the specialisation, it changes the behaviour of the other TU (the specialisation is not used in both TUs)
Here is a complete example describing my issue:
check.h: defines the class template which can be specialised for user defined types
#pragma once
#include <iostream>
template<typename T>
struct Check
{
static void type();
};
template<typename T>
void Check<T>::type()
{
std::cout << "check fall-back\n";
}
template<typename T>
void check(T&&)
{
Check<T>::type();
}
type.h: definition of my user-defined type
#pragma once
enum Foo
{
FOO,
BAR
};
type_check.h: specialises Check for Foo
#pragma once
#include "type.h"
#include "check.h"
template<>
struct Check<Foo>
{
static void type()
{
std::cout << "check Foo\n";
}
};
lib.h: TU header file
#pragma once
void lib();
lib.cpp: TU source file - uses the specialisation from type_check.h
#include "lib.h"
#include "type_check.h"
void lib()
{
check(FOO);
}
main.cpp:
#include "check.h"
#include "type.h"
#include "lib.h"
#include "type_check.h" // uncomment this to make specialisation avail to all
int main()
{
check(5);
lib();
// check(FOO); // uncomment this to change behaviour of lib()`
return 0;
}
Results:
Calling lib() without calling check(FOO) in main results in the following:
check fall-back
check Foo
Calling lib() and check(FOO) in main results in the following:
check fall-back
check fall-back <-- main changes behaviour of lib
check fall-back
Including type_check.h in main.cpp, and then calling lib() and check(FOO) in main results in the following:
check fall-back
check Foo
check Foo
Question:
Why does calling check(FOO) in a separate TU when the Check<Foo> specialisation is not available remove it from the overload set in lib.cpp?
Notes:
I can't just put the Check<Foo> specialisation in the same file as the definition of Foo, as Foo is actually a generated file (protobuf)
This is a violation of the One Definition Rule. The linker sees two function definitions for the same function and will pick one. No diagnostic is required.
In this case, void Check<Foo>::type is defined once by the instantiation of the template definition from check.h used in lib.cpp, while the other definition is from type_check.h used in main.cpp.

C++: Class method using function defined in main

So I have a class:
class MyClass
public:
printSomeStuff() { //Including implementation here to save space
print(data);
}
private:
int data;
And a main program, with a template function defined outside:
template<typename T>
void print(T val) {
cout << val;
}
int main() {
MyClass a;
a.printSomeStuff();
}
The idea is that I could move MyClass somewhere else and be fine, but a new print function would need to be defined based on the scenario. Typically this would just be a cout.
If I try to actually use this style of coding, though, I get an error because print is not defined in MyClass.cpp.
How should I address this issue?
You should move your print() function into a header (and a suitable namespace) and include it into the translation units where it is needed, e.g.:
// print.h
#ifndef INCLUDED_PRINT
#define INCLUDED_PRINT
#include <iostream>
namespace utilities {
template <typename T>
void print(T const& val) {
std::cout << val;
}
}
#endif
You'd then include this header into the translation where it is used, e.g.
// MyClass.h
#ifndef INCLUDED_MYCLASS
#define INCLUDED_MYCLASS
#include "print.h"
class MyClass
public:
printSomeStuff() { //Including implementation here to save space
utilities::print(data);
}
private:
int data;
};
#endif
Put your template definition in its own header file and include it in your class implementation file.
That said, with something as trivial as printing, it may be must as easy to do it in the printSomeStuff method entirely. The extra indirection isn't really buying you anything.
The header in which print template is defined has to be accessible from the header in which MyClass is defined, but not necessarily from main, so you could move it to a separated header and include it from MyClass.hpp or even MyClass.cc

CRTP, forward declarations and templates in cpp files

I'm using the CRTP pattern to create an interface, which other classes will derive from.
In the interface I forward declare a structure (important because I don't want to drag other stuff in the interface), but I include its definition in the cpp file which defines the interface.
Interface.h
#ifndef INTERFACE_H_INCLUDED
#define INTERFACE_H_INCLUDED
// forward declaration
class ForwardDecl;
template <class Derived>
class Interface
{
public:
ForwardDecl interfaceMethod();
};
#endif // INTERFACE_H_INCLUDED
ForwardDecl.h
#ifndef FORWARDDECL_H_INCLUDED
#define FORWARDDECL_H_INCLUDED
struct ForwardDecl
{
ForwardDecl(int i):internal(i)
{}
int internal;
};
#endif // FORWARDDECL_H_INCLUDED
Interface.cpp
#include "Interface.h"
#include "ForwardDecl.h"
template<class Derived>
ForwardDecl Interface<Derived>::interfaceMethod()
{
return static_cast<Derived *>(this)->implementation_func();
}
And this is the implementation which implements the interface
Implementation.h
#ifndef IMPLEMENTATION_H_INCLUDED
#define IMPLEMENTATION_H_INCLUDED
#include "Interface.h"
class ForwardDecl;
class Implementation: public Interface<Implementation>
{
friend class Interface<Implementation>;
private:
ForwardDecl implementation_func();
};
#endif // IMPLEMENTATION_H_INCLUDED
Implementation.cpp
#include "Implementation.h"
#include "ForwardDecl.h"
#include <iostream>
struct ForwardDecl Implementation::implementation_func()
{
ForwardDecl fd(42);
std::cout << fd.internal << std::endl;
return fd;
}
And the main file
#include <iostream>
#include "Implementation.h"
#include "ForwardDecl.h"
using namespace std;
int main()
{
Implementation impl;
ForwardDecl fd = impl.interfaceMethod();
cout << fd.internal << endl;
return 0;
}
I get linking errors on both VS and GCC.
Any workaround? Thank you.
There is a flaw in your very approach: You have a public function returning a ForwardDecl instance, so every client wanting to use this function also must include the according definition of that type, which implies you can make that type public from the beginning. This includes making the function definition inline, which will fix your linker problems.
However, if you really want to hide the content of that structure and you are sure clients don't need it directly, you can declare it and then pass around references to such a structure (or pointers, but raw pointers are evil albeit not in the same league of evil as #macros). In that case, I would still make the function definition inline.
If you really, really want to not make the function inline, you can also explicitly instantiate the function template for the types that you need. You would add at the end of the template's .cpp file something like template class Interface<int>; (I don't remember the exact syntax so take that with a few flakes of fleur de sel, check out the C++ FAQ at parashift.com for more info). This makes the template a little less universal though, as it requires adjustments for any type that you want to use it with, but it can be an approach in some corner cases.
The definitions of function templates and member functions of class templates need to be visible in all translation units that instantiate those templates. That is, you shouldn't put template definitions in a .cpp file, which means you need to move the contents of Interface.cpp up into Interface.h.

Expected initializer before '<' token

I have a template class myClass prototyped in a header file, and am implementing it in a .cpp file that is included at the end of the header file. When I use the code:
template<typename T>
class myClass {
public:
void myFunction(const T item);
};
in the header file and
template <class T>
void myClass<T>::myFunction(const T item)
{
//stuff
}
in the implementation file, I get the above error on line 2 of the implementation code. I have used this same exact syntax in another program with successful compilation and correctly functioning results, so I am quite confused. There are three different function definitions in the .cpp file and all have this same error on their respective lines. I assume I am making a small error but I really can't seem to figure it out.
Help and explanation are very much appreciated.
EDIT:
Here is an SSCCE which has the same error:
main.cpp
#include <iostream>
#include "myClass.h"
using namespace std;
int main(){
myClass<int> example;
example.myFunction(1);
return 0;
}
myClass.h
#include<iostream>
#ifndef MYCLASS_H_
#define MYCLASS_H_
template<typename T>
class myClass {
public:
void myFunction(const T item);
};
#include "myClass.cpp"
#endif /* MYCLASS_H_ */
myClass.cpp
using namespace std;
template <class T>
void myClass<T>::myFunction(const T item)
{
cout << "Hello World!";
}
and I am using Code::Blocks 10.05 with the GNU GCC compiler.
I finally solved the problem by removing the myClass.cpp from the build configuration. Not sure why this was necessary, but it works perfectly now.
Put the implementation of the method in the header file (.h) too
The compiler needs to know details of implementation in translation unit.
It is very difficult to declare a template in an .h file and define it in a .cpp file. The compiler needs template declaration and definition in a single file in order to create the code. So if your compiler does not support export keyword it won't work.
So you should not use different files for declaration and definition. See also this thread.
Templates are instantiated on demand and given the complexities which would be induced in compiler design most of the compilers build a restriction to keep the template declaration and definition in one single file. If not so, template declaration on top of class and function definitions would create a pattern difficult for the compiler to detect a pattern and instantiate the template.
Similar question has been discussed on Stackoverflow, and explained on Parashift and cplusplus.com (Read: Templates and multiple-file projects at the end of the article).
Hope this helps!
Vivek
Keep implementation in myClass.cpp file is also possible. Apart from the implementation itself, you need to put declarations with specific types of T. For example, if T could be int and float, myClass.cpp should be like:
using namespace std;
template <class T>
void myClass<T>::myFunction(const T item)
{
cout << "Hello World!";
}
// Declarations with specific types.
template void myClass<int>::myFunction(const int item);
template void myClass<float>::myFunction(const float item);

undefined reference to <std::string>std::string& [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why do I get “unresolved external symbol” errors when using templates?
“undefined reference” to a template class function
I got error on line: Console::getInstance()->readObjectData(a); in main.cpp
undefined reference to void Console::readObjectData<std::string>std::string&)
Console.h
http://pastebin.com/WsQR7JNq
#define CONSOLE_H
#include <string>
using namespace std;
class Console
{
public:
static Console* getInstance();
template <typename T>
void readObjectData(T& o);
protected:
private:
Console(); // Private so that it can not be called
Console(Console const&); // copy constructor is private
Console& operator=(Console const&); // assignment operator is private
static Console* m_pInstance;
};
#endif // CONSOLE_H
Console.cpp
http://pastebin.com/N02HjgBw
#include "Console.h"
#include "Log.h"
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
// Global static pointer used to ensure a single instance of the class.
Console* Console::m_pInstance = NULL;
Console::Console()
{
}
Console::Console(Console const&)
{
}
Console& Console::operator=(Console const&)
{
}
Console* Console::getInstance()
{
if (!m_pInstance) // Only allow one instance of class to be generated.
m_pInstance = new Console;
return m_pInstance;
}
template <typename T>
void Console::readObjectData(T& o) {
//cin >> o;
}
main.cpp
http://pastebin.com/U6qAJUN1
#include "Console.h"
using namespace std;
int main()
{
string a;
Console::getInstance()->readObjectData(a);
return 0;
}
any ideas?
You cannot define template<>'d function in .cpp file.
Move
template <typename T>
void Console::readObjectData(T& o) {
//cin >> o;
}
To header file.
You did not implemented this method. You have to provide implementation for your template in .h file
Because you've not put the implementation of readObjectData in the header, you will need to provide an explicit specialization of the function - one that takes std::string&.
This should go in Console.cpp:
template <>
void Console::readObjectData(string& o) {
//cin >> o;
}
You cannot place your template method implementation in Console.cpp it must appear in the header file, or you must implement an explicit specialization for std::string.
The definition for the templated function (readObjectData) has to be inlined, not in a .cpp file.
The compiler when it see's a class with a templated function, or a templated class, makes a copy of the entire class with the new type stuck in there. So if you stick the definition of the function in the .cpp file, the compiler will not know where the implementation is because it doesn't exist.
In the process of converting some C++ files to the output( executive, shared library or ... ) 2 tools will co-operate, first compiler that create object files and then linker that convert those objects to the output. What you should know is that linker has nothing to do with template( except in special case of explicit instantiation ), and templates will be instantiated by compiler and another note is compiler work with each source files and headers that included in that source file and ignore all other files of your project. So when compiler want to compile main.cpp it see no implementation of readObjectData and thus it can't generate any code in the object files for that function, and when linker want to link objects to result it will never find an implementation for that function! So the easiest way is to move your implementation of readObjectData to the .h file and every thing will work as expected.