Templated class parameters to outside function [duplicate] - c++

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 9 years ago.
Is it possible to pass the template-parameters to a function somewhere else defined?
For instance I have the class
Barrier.pp
template<Location L, Knock K>
class Barrier
{
//...
void checkBarrier( ... )
{
BarrierBest_checkBarrier<L, K>( ... );
}
//...
}
Other.cpp
template<Location L, Knock K>
BarrierBest_checkBarrier( ... )
{
//Use L and K to do call other function
}
As I have it right now the compiler throws a unresolved external symbol for all the possible combinations of the template parameters, that is, BarrierBest_checkBarrier<1,1>, BarrierBest_checkBarrier<1,0>, BarrierBest_checkBarrier<0,1>, BarrierBest_checkBarrier<0,0>
Is there a way to make this work?

If there are a limited number of combinations, you can explicitly instantiate your template, allowing you to keep your code separated between header and source files.
Put this at the bottom of your source file
template void BarrierBest_checkBarrier<0, 0>(...);
template void BarrierBest_checkBarrier<0, 1>(...);
template void BarrierBest_checkBarrier<1, 0>(...);
template void BarrierBest_checkBarrier<1, 1>(...);
If you want other files calling your function to pick their own parameters not in this list, you must put the whole templated code into a header file.

The problem may be that your templated functions are in cpp files, not in headers. The template parameters have to be known at the compile time. If you have separate compilation units, they are not.

Related

Undefined reference when using pointers [duplicate]

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 7 years ago.
I have no idea why this is happenning, since I think I have everything properly declared and defined.
I have the following program, designed with templates. It's a simple implementation of a queue, with the member functions "add", "substract" and "print".
I have defined the node for the queue in the fine "nodo_colaypila.h":
#ifndef NODO_COLAYPILA_H
#define NODO_COLAYPILA_H
#include <iostream>
template <class T> class cola;
template <class T> class nodo_colaypila
{
T elem;
nodo_colaypila<T>* sig;
friend class cola<T>;
public:
nodo_colaypila(T, nodo_colaypila<T>*);
};
Then the implementation in "nodo_colaypila.cpp"
#include "nodo_colaypila.h"
#include <iostream>
template <class T> nodo_colaypila<T>::nodo_colaypila(T a, nodo_colaypila<T>* siguiente = NULL)
{
elem = a;
sig = siguiente;//ctor
}
Afterwards, the definition and declaration of the queue template class and its functions:
"cola.h":
#ifndef COLA_H
#define COLA_H
#include "nodo_colaypila.h"
template <class T> class cola
{
nodo_colaypila<T>* ult, pri;
public:
cola<T>();
void anade(T&);
T saca();
void print() const;
virtual ~cola();
};
#endif // COLA_H
"cola.cpp":
#include "cola.h"
#include "nodo_colaypila.h"
#include <iostream>
using namespace std;
template <class T> cola<T>::cola()
{
pri = NULL;
ult = NULL;//ctor
}
template <class T> void cola<T>::anade(T& valor)
{
nodo_colaypila <T> * nuevo;
if (ult)
{
nuevo = new nodo_colaypila<T> (valor);
ult->sig = nuevo;
ult = nuevo;
}
if (!pri)
{
pri = nuevo;
}
}
template <class T> T cola<T>::saca()
{
nodo_colaypila <T> * aux;
T valor;
aux = pri;
if (!aux)
{
return 0;
}
pri = aux->sig;
valor = aux->elem;
delete aux;
if(!pri)
{
ult = NULL;
}
return valor;
}
template <class T> cola<T>::~cola()
{
while(pri)
{
saca();
}//dtor
}
template <class T> void cola<T>::print() const
{
nodo_colaypila <T> * aux;
aux = pri;
while(aux)
{
cout << aux->elem << endl;
aux = aux->sig;
}
}
Then, I have a program to test these functions as follows:
"main.cpp"
#include <iostream>
#include "cola.h"
#include "nodo_colaypila.h"
using namespace std;
int main()
{
float a, b, c;
string d, e, f;
cola<float> flo;
cola<string> str;
a = 3.14;
b = 2.71;
c = 6.02;
flo.anade(a);
flo.anade(b);
flo.anade(c);
flo.print();
cout << endl;
d = "John";
e = "Mark";
f = "Matthew";
str.anade(d);
str.anade(e);
str.anade(f);
cout << endl;
c = flo.saca();
cout << "First In First Out Float: " << c << endl;
cout << endl;
f = str.saca();
cout << "First In First Out String: " << f << endl;
cout << endl;
flo.print();
cout << endl;
str.print();
cout << "Hello world!" << endl;
return 0;
}
But when I build, the compiler throws errors in every instance of the template class:
undefined reference to `cola(float)::cola()'... (it's actually cola'<'float'>'::cola(), but this doesn't let me use it like that.)
And so on. Altogether, 17 warnings, counting the ones for the member functions being called in the program.
Why is this? Those functions and constructors WERE defined. I thought that the compiler could replace the "T" in the template with "float", "string" or whatever; that was the advantage of using templates.
I read somewhere here that I should put the declaration of each function in the header file for some reason. Is that right? And if so, why?
This is a common question in C++ programming. There are two valid answers to this. There are advantages and disadvantages to both answers and your choice will depend on context. The common answer is to put all the implementation in the header file, but there's another approach will will be suitable in some cases. The choice is yours.
The code in a template is merely a 'pattern' known to the compiler. The compiler won't compile the constructors cola<float>::cola(...) and cola<string>::cola(...) until it is forced to do so. And we must ensure that this compilation happens for the constructors at least once in the entire compilation process, or we will get the 'undefined reference' error. (This applies to the other methods of cola<T> also.)
Understanding the problem
The problem is caused by the fact that main.cpp and cola.cpp will be compiled separately first. In main.cpp, the compiler will implicitly instantiate the template classes cola<float> and cola<string> because those particular instantiations are used in main.cpp. The bad news is that the implementations of those member functions are not in main.cpp, nor in any header file included in main.cpp, and therefore the compiler can't include complete versions of those functions in main.o. When compiling cola.cpp, the compiler won't compile those instantiations either, because there are no implicit or explicit instantiations of cola<float> or cola<string>. Remember, when compiling cola.cpp, the compiler has no clue which instantiations will be needed; and we can't expect it to compile for every type in order to ensure this problem never happens! (cola<int>, cola<char>, cola<ostream>, cola< cola<int> > ... and so on ...)
The two answers are:
Tell the compiler, at the end of cola.cpp, which particular template classes will be required, forcing it to compile cola<float> and cola<string>.
Put the implementation of the member functions in a header file that will be included every time any other 'translation unit' (such as main.cpp) uses the template class.
Answer 1: Explicitly instantiate the template, and its member definitions
At the end of cola.cpp, you should add lines explicitly instantiating all the relevant templates, such as
template class cola<float>;
template class cola<string>;
and you add the following two lines at the end of nodo_colaypila.cpp:
template class nodo_colaypila<float>;
template class nodo_colaypila<std :: string>;
This will ensure that, when the compiler is compiling cola.cpp that it will explicitly compile all the code for the cola<float> and cola<string> classes. Similarly, nodo_colaypila.cpp contains the implementations of the nodo_colaypila<...> classes.
In this approach, you should ensure that all the of the implementation is placed into one .cpp file (i.e. one translation unit) and that the explicit instantation is placed after the definition of all the functions (i.e. at the end of the file).
Answer 2: Copy the code into the relevant header file
The common answer is to move all the code from the implementation files cola.cpp and nodo_colaypila.cpp into cola.h and nodo_colaypila.h. In the long run, this is more flexible as it means you can use extra instantiations (e.g. cola<char>) without any more work. But it could mean the same functions are compiled many times, once in each translation unit. This is not a big problem, as the linker will correctly ignore the duplicate implementations. But it might slow down the compilation a little.
Summary
The default answer, used by the STL for example and in most of the code that any of us will write, is to put all the implementations in the header files. But in a more private project, you will have more knowledge and control of which particular template classes will be instantiated. In fact, this 'bug' might be seen as a feature, as it stops users of your code from accidentally using instantiations you have not tested for or planned for ("I know this works for cola<float> and cola<string>, if you want to use something else, tell me first and will can verify it works before enabling it.").
Finally, there are three other minor typos in the code in your question:
You are missing an #endif at the end of nodo_colaypila.h
in cola.h nodo_colaypila<T>* ult, pri; should be nodo_colaypila<T> *ult, *pri; - both are pointers.
nodo_colaypila.cpp: The default parameter should be in the header file nodo_colaypila.h, not in this implementation file.
You will have to define the functions inside your header file.
You cannot separate definition of template functions in to the source file and declarations in to header file.
When a template is used in a way that triggers its intstantation, a compiler needs to see that particular templates definition. This is the reason templates are often defined in the header file in which they are declared.
Reference:
C++03 standard, ยง 14.7.2.4:
The definition of a non-exported function template, a non-exported member function template, or a non-exported member function or static data member of a class template shall be present in every translation unit in which it is explicitly instantiated.
EDIT:
To clarify the discussion on the comments:
Technically, there are three ways to get around this linking problem:
To move the definition to the .h file
Add explicit instantiations in the .cpp file.
#include the .cpp file defining the template at the .cpp file using the template.
Each of them have their pros and cons,
Moving the defintions to header files may increase the code size(modern day compilers can avoid this) but will increase the compilation time for sure.
Using the explicit instantiation approach is moving back on to traditional macro like approach.Another disadvantage is that it is necessary to know which template types are needed by the program. For a simple program this is easy but for complicated program this becomes difficult to determine in advance.
While including cpp files is confusing at the same time shares the problems of both above approaches.
I find first method the easiest to follow and implement and hence advocte using it.
This link explains where you're going wrong:
[35.12] Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?
Place the definition of your constructors, destructors methods and whatnot in your header file, and that will correct the problem.
This offers another solution:
How can I avoid linker errors with my template functions?
However this requires you to anticipate how your template will be used and, as a general solution, is counter-intuitive. It does solve the corner case though where you develop a template to be used by some internal mechanism, and you want to police the manner in which it is used.

C++ static member of class template -- linker warning "multiple definition" [duplicate]

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Static member initialization in a class template
(3 answers)
Closed 4 years ago.
Let's say for some reason, I want to have a class template MyTemp with some static data member smDummyVar :
Mytemp.h
#ifndef MY_TEMP_H
#define MY_TEMP_H
template<class T>
class MyTemp{
...
private:
static int smDummyVar;
...
};
#include "MyTemp.cpp"
#endif //MY_TEMP_H
Mytemp.cpp
...
template<class T> int MyTemp<T>::smDummyVar = 0;
...
Since the compiler requires that the definition and declaration of a template be at the same place, so I include MyTemp.cpp in MyTemp.h .
Now: I want to use MyTemp at many places and create objects using the template:
case1.cpp
#include "MyTemp.h"
void dummyfunc1(){
MyTemp<int> myTemp1;
}
case2.cpp
#include "MyTemp.h"
void dummyfunc2(){
MyTemp<int> myTemp2;
}
I won't get any error from the compiler, but I'd get warning from the linker:
"multiple definition for MyTemp<int>::smDummyVar" ... defined in invalid_group(case1.o) ... rejected in favour of symbol defined in ...(case2.o)
Question: how can I get rid of this warning ?
Thanks a lot in advance for your help !
====================================
inspired by one of the answers in this thread Why can templates only be implemented in the header file?
I found the following solution:
i. remove #include "MyTemp.cpp" in MyTemp.h
ii. specialized.h
#include "MyTemp.h"
typedef MyTemp<int> MySpecialized;
iii. specialized.cpp
#include "MyTemp.cpp"
template class MyTemp<int>;
iv. give specialized.cpp to cmake file
v. include specilized.h in case1.cpp and case2.cpp
the "multiple definition" warning issued by the linker will go away.
Thank you guys for helping !

Is it possible inherit from Template class C++ specialized on himself [duplicate]

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 5 years ago.
Let's say we have base class Table
template <typename T>
class Table
{
public:
Table();
virtual ~Table() = default;
private:
// get all column names as list
virtual std::list<std::string> getAllColumnsImpl();
};
and I want inherit TestTable class and override method getAllColumnsImpl from base class:
class TestTable :
public Table<TestTable>
{
public:
TestTable();
virtual ~TestTable() = default;
std::string Description;
int Count;
private:
// get all column names as list
std::list<std::string> getAllColumnsImpl() override;
};
Is it possible in general ?
For example I have linker errors like:
error LNK2019: unresolved external symbol "public: __cdecl Table<class TestTable>::Table<class TestTable>(void)" (??0?$Table#VTestTable####QEAA#XZ) referenced in function "public: __cdecl TestTable::TestTable(void)" (??0TestTable##QEAA#XZ)
You can do it, it's called CRTP - the Curiously Recurring Template Parameter. It's very handy and there are many blogs and resources explaining uses for it.
The error you're getting is because you need to have the template's function bodies in the template's header file.
Each cpp file is compiled to a separate object file, and templates are resolved on a per-cpp file basis. When you put template code in a cpp file, then it's just "template < T >" and the compiler doesn't know what T is, so no code is generated (unless it's requested from the same cpp file, with an actual type and not T).
However, your other cpp file knows that it wants a "template < TestTable >", but it doesn't have access to the code that would make that work, because that's stuck in the other cpp file, which only knows the generic "template < T >". Neither cpp file is able to generate the missing code, so you get the linker error. Putting all the template code together in the header file removes the issue.

C++ Template errors? [duplicate]

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 6 years ago.
I'm trying to learn how to use templated classes. I've created a simple templated class numbers that holds 2 numbers that can be any data type. Then I made a method that returns the bigger number of the two in the object. For some reason I keep getting linker errors though... Here's the errors and code. Not sure what's wrong, Visual Studio didn't underline anything in my code.
They say "unresolved external symbol" if it's too small to read.
templated.h
template <class T>
class numbers {
public:
numbers(T x, T y);
T bigger();
private:
T a, b;
};
templated.cpp
#include "templated.h"
#include <iostream>
using namespace std;
template <class T>
numbers<T>::numbers(T x, T y) {
a = x;
b = y;
}
template <class T>
T numbers<T>::bigger() {
return a > b ? a : b;
}
main.cpp
#include <iostream>
#include "templated.h"
using namespace std;
int main() {
numbers <int>pair(1, 2);
cout << pair.bigger() << endl;
return 0;
}
Thanks for reading!
You're not supposed to put template implementations in a cpp/c file. Move them all to your .h file.
This is because cpp files are supposed to take functions that compile into implementation libraries (like dll files or compiled objects), while template functions have undefined types (yet), whose types get defined at compile time.
You can, however, put specializations of your template functions in the cpp file, where you specify what types you want to include in your compiled objects.

Why does a member function exist only once even defined in one multiple included .h file? [duplicate]

This question already has answers here:
How can a C++ header file include implementation?
(7 answers)
Closed 6 years ago.
I am just wondering how the compiler can handle the situation where a member function is declared & defined only in a include file but this .h file is included multiple times in different source codes without complains of the linker regarding multiple definition of ....
foo_1.h:
class foo
{
public:
auto in_include() -> void { printf( "in in_include()\n" ); }
foo();
};
foo_1.cpp:
#include <stdio.h>
#include "foo_1.h"
foo::foo()
{
printf( "in foo()\n" );
in_include();
}
and finally foo_main.cpp:
#include <stdio.h>
#include "foo_1.h"
int main()
{
foo fooObject;
}
These MCVE compiles and links fine and produces the expected output:
in foo()
in in_include()
BUT, when I add in foo_1.h this line int globar_var; then the linker complains [as I expect it]:
/tmp/ccfjJJAT.o:(.bss+0x0): multiple definition of `globar_var'
/tmp/cciob9sM.o:(.bss+0x0): first defined here
I do not consider as a duplicate because I ask why the linker does not complain. The other question is more or less asking why a function can be defined in a header file.
Class member functions that are defined with a body within the class declaration automatically become inline functions, and therefore it's OK even if the definition is compiled multiple times. You can get the same for non-class functions by using the inline keyword.
How this is implemented in practice is up to the compiler - it could actually inline the code every time it's called (think copy and paste), or it could arrange for some linker magic I don't fully understand to happen that prevents the collision.