This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 4 months ago.
The community reviewed whether to reopen this question 4 months ago and left it closed:
Original close reason(s) were not resolved
Defining a class with the template generics is not letting me compile this class.
I have the following three files:
Class Definition:
#ifndef _myclass_h
#define _myclass_h
template <typename ValueType>
class myClass {
public:
myClass();
};
#endif
Class Implementation:
#include "myClass.h"
template <typename ValueType>
myClass<ValueType>::myClass() { }
And the test file:
#include "myClass.h"
int main() {
myClass<int> cls;
return 0;
}
I'm compiling it on a MacBook Air (M1, 2020) running a MacOs Big Sur version 11.6 (20G165).
And when running this command:
g++ -std=c++11 -o testMyClass myClass.cpp testMyClass.cpp
I'm getting this error:
Undefined symbols for architecture arm64:
"myClass<int>::myClass()", referenced from:
_main in testMyClass-595230.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [testMyClass] Error 1
It seems that for some reason the compiler is not able to find the class constructor definition in myClass.cpp. If I take the template header in all of the classes and make the proper adaptations, the class is compiled.
Does anyone have a clue on how to solve that?
I was able to implement the idea suggest here by doing the following.
In myClass.cpp I commented out the inclusion, ending up with:
/* #include "myClass.h" */
template <typename ValueType>
myClass<ValueType>::myClass() { }
And included myClass.cpp to myClass.h, like this (last line):
#ifndef _myclass_h
#define _myclass_h
template <typename ValueType>
class myClass {
public:
myClass();
};
#endif
#include "myClass.cpp"
Aesthetically, I consider this to be an ugly solution, but it works.
Related
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 !
I have seen many related questions to this problem, but after carefully following advice from members, my problem still persists. The code is quite simple. I only have the following header file ("instrument.h"), which contains the base class and the template class:
#include <stdio.h>
#include <string>
using namespace std;
class Instrument
{
public:
Instrument();
virtual void print() const = 0;
};
template <class parameter> class Equity : public Instrument
{
public:
Equity();
virtual void print() const;
};
Now, in my main function on main.cpp I only do the following:
#include "instrument.h"
#include <iostream>
int main() {
Equity<double> pb;
return 0;
}
Well, I get the very well-known error:
Undefined symbols for architecture x86_64:
"Equity<double>::Equity()", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I have already changed in Build Settings the C++ standard library to libstdc++, also to default compiler, and so on. Do I have a problem with my project settings? Is perhaps the template wrongly implemented? I was thinking I should also have a instrument.cpp file, but then again definitions for templates must be kept in the header file so that would probably crash too.
Thanks in advance
You declared the default constructors for both Instrument and Equity but defined them nowhere.
Alter their definitions appropriately:
public:
Equity() = default; // Or {} in pre-C++11
// ^^^^^^^^^
(And equivalently for Instrument)
You can also completely omit the declarations of any default constructors for now since you didn't declare any other constructors in both Equity and Instrument and the default constructors will be generated automatically.
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 8 years ago.
The question is how to call the base constructor from an inherited template class. I want to create a FixedQueue and overload some function in std::queue. Therefore std:queue is the base class. The keyword using, since c++11, can be used to call the base and it works if this is a specialised class, but I cannot get it working with a template class.
Furthermore I tried it to use the old c++ standard in which I simply invoke the defined constructors in std::queue. However it doesn't work.
h file
#ifndef _HEADER_FIXED_QUEUE_
#define _HEADER_FIXED_QUEUE_
#include <queue>
#include <iostream>
template<class T>
class FixedQueue : public std::queue<T>
{
//using queue<T>::queue<T>;
public:
FixedQueue();
FixedQueue(const T &initial_var);
void foo() { std::cout << "inside\n"; }
};
#endif
cpp file
#include "FixedQueue.h"
template<typename T>
FixedQueue<T>::FixedQueue()
:
std::queue<T>()
{
std::cout << "Default Constructor FixedQueue\n";
}
template<typename T>
FixedQueue<T>::FixedQueue(const T &initial_var)
:
std::queue<T>(initial_var)
{
std::cout << "Specialized Constructor FixedQueue\n";
}
main file.
#include <iostream>
#include "FixedQueue.h"
int main()
{
FixedQueue<int> d_frameSlices;
std::cout << "I want to do something with my queue\n";
}
The question is thus. How do I chain the constructors to the defined constructors in the base class std::queue. The template thing is killing me.
This is the error message I obtain from clang, which is the usual undefined reference.
Undefined symbols for architecture x86_64:
"FixedQueue<int>::FixedQueue()", referenced from:
_main in main-lqoFSA.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
If someone knows how to do this with "using" or the old fashion way I am happy with both. Thanks in advance
you should not put the template in cpp file put it all in header file
Hi everybody I just wanted to practice some c++ template but i get linker errors. Can anybody help me please?
Here is my code:
// File: MyClass.h
#ifndef _MYCLASS_H
#define _MYCLASS_H
template<class T> class MyClass {
T value;
public:
MyClass(T v);
~MyClass();
};
#endif // _MYCLASS_H
// File: MyClass.cpp
#include "MyClass.h"
template<class T> MyClass<T>::MyClass(T v) {
value = v;
}
template<class T> MyClass<T>::~MyClass() {
}
// File: main.cpp
#include "MyClass.h"
int main() {
MyClass<int> test(10);
return 0;
}
Here is command line output:
g++ main.cpp -c
g++ MyClass.cpp -c
g++ main.o MyClass.o -o Out
main.o: In function `main':
main.cpp:(.text+0x1a): undefined reference to `MyClass<int>::MyClass(int)'
main.cpp:(.text+0x2b): undefined reference to `MyClass<int>::~MyClass()'
collect2: ld returned 1 exit status
make: *** [all] Error 1
As you can see I'm using Ubuntu 10.04 and GNU C++ Compiler.
Am I missing something in this code?
Thanks for replies. It works but isn't there a better way to protect the code?
For example what if I want to create a non-opensource library?!
I want to export the code to a static library. and link the library to other projects ...
You have to put full template into the header. Compiler needs to see the body of the template methods at the site of template instantiation - main.cpp in your case. See, for example, C++ FAQ.
You should put template classes and inline methods into header files. You can't seperate definition and implementation in their case.
#Nikolai N Fetissov has the right solution. I would add to this that a nice way to do this, if you want to keep the implementation and templated function definitions separate is that you can put the implementations into MyClass.hxx and include it at the end of your MyClass.h
// File: MyClass.h
#ifndef _MYCLASS_H
#define _MYCLASS_H
template<class T> class MyClass
{
T value;
public:
MyClass(T v);
~MyClass();
};
#include "MyClass.hxx" /// <--- like this
#endif // _MYCLASS_H
It's important to remember what a template is. It is a template for generating code if needed; it is not code itself.
So declaring a template class and writing implementations for those methods does not generate any object code for that class; it simply provides a template for doing so if necessary.
When a template class is instantiated with an actual argument, the compiler will generate the code from the template class. In order to do that, it needs to be able to see the the templates. But since you've only #includeed the .h file, and the implementation of the methods in in the .cpp file, the compiler won't be able to generate the object code for the function implementations. Then, when the linker looks for those definitions it won't find it.
All of this is a long-winded way of getting to the same result the other answers did -- you need to put the implementation in the header file with the class declaration. But it may help to know why that is.
I am using templates for the first time in C++ and running into a problem when I try to compile. Basically trying to create my own basic ArrayList of sorts:
The .hpp:
#ifndef ARRAYLIST_HPP_
#define ARRAYLIST_HPP_
template <class T>
class ArrayList
{
private:
int current, top ;
T * al ;
public:
ArrayList() ; // default constructor is the only one
};
#endif /* ARRAYLIST_HPP_ */
The .cpp:
#include "ArrayList.hpp"
using namespace std ;
//template <class T>
//void memoryAllocator( T * p, int * n ) ; // private helper functions headers
template <class T>
ArrayList<T>::ArrayList()
{
current = 0 ;
top = 10 ;
al = new T[top] ;
}
The main:
#include "ArrayList.hpp"
int main()
{
ArrayList<int> test ;
}
When I try to build without the main it compiles fine, however, as soon as I try to use it in the main I get the following error:
Undefined symbols for architecture x86_64:
"ArrayList<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::ArrayList()", referenced from:
_main in Website.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
make: *** [APProject2] Error 1
Any thoughts as to what might be the problem would be much appreciated!
Cheers!
Templates need to be declared and defined in the header.
Also: I don't think that is the real error. It mentions an instantiation of ArrayList<std::string> which I can't see anywhere.
This FAQ entry explains why.
You need to include the implementation in the .hpp file. The compiler needs to know T at compile time to generate the specialization.
You can't put the templated code into a separate .cpp file... your constructor should be in the ArrayList header. The point is that it's only when main() is compiled that the compiler realises it needs to instantiate ArrayList and what type T will take, and so it needs to have the code available to do the instantiation....