I am attempting to create a dynamic memory for this class i have created:
#ifndef STACK_H
#define STACK_H
#include <stdexcept>
#include "Link.h"
template <class T>
struct stack{
Link<T> * head;
stack();
void push(T * data);
T* top();
T* pop();
void cleanup();
};
#endif
src file:
#include "stack.h"
#include <cstddef>
template <class T>
stack<T>::stack(){
head=nullptr;
}
driver:
#include "stack.h"
#include <iostream>
#include <memory>
int main(){
stack<double> oneStack();
stack<double> * oneStack2=new stack<double>;
}
When I compile the code I get the following error:
g++ -Wall driver.o Link.o stack.o -o driver.exe
driver.o: In function main':
driver.cpp:(.text+0x1c): undefined reference tostack::stack()'
for some reason using the new keyword is causing this error?
When you are writing template class, you need to define function in the same place where you declare it, so you should probably write it like this
#ifndef STACK_H
#define STACK_H
#include <stdexcept>
#include "Link.h"
template <class T>
struct stack{
Link<T> * head;
stack()
{
// Constructor code goes here
}
void push(T * data)
{
// Method code goes here
}
T* top()
{
// Method code goes here
}
T* pop()
{
// You get the idea
}
void cleanup()
{
// ...
}
};
#endif
The reason why compiler needs the template classes and functions to be declared and defined in the same place is that it actually generates a new class for every different set of templates parameters that are used in your code. So, imagine you have .h file with declaration of template class and it's methods, and you have a .cpp file where these methods are defined. The compiler tries to compile .cpp file into an .obj file that will later be used to link code into a single executable or library file. But it can't do so, because it doesn't have template parameters right now in this file, so it can't actually generate a concrete code for a concrete parameters. Something like this.
If you want a better insight, you can look here: http://isocpp.org/wiki/faq/templates#templates-defn-vs-decl
Related
I'm working on creating an "Array_Base" interface that will allow a user to create either a fixed array or an expandable array of any type. Right now I can't even get the regular Array to work.
I've broken the problem down to a few of its simplest components to try and isolate the issue. I believe it has something to do with my instantiation. I'm using Visual Studio to run the code.
Array_Base.h
#ifndef _ARRAY_BASE_H_
#define _ARRAY_BASE_H_
#include <cstring> // for size_t definition
template <typename T>
class Array_Base
{
public:
typedef T type;
//Default Constructor
virtual void Array_Base(void) = 0;
// Destructor.
virtual ~Array_Base(void) = 0;
protected:
/// Pointer to the actual data.
T* data_;
/// Current size of the array.
size_t cur_size_;
/// Maximum size of the array.
size_t max_size_;
};
#endif // !defined _ARRAY_H_
Array.h
#ifndef _ARRAY_H_
#define _ARRAY_H_
#include <cstring> // for size_t definition
#include "Array_Base.h"
template <typename T>
class Array : public Array_Base
{
public:
/// Type definition of the element type.
typedef T type;
/// Default constructor.
Array (void);
///Destructor
~Array (void);
};
#include "Array.cpp"
#include "Array.inl"
#endif // !defined _ARRAY_H_
Array.cpp
#include <stdexcept> // for std::out_of_bounds exception
#include <iostream>
#define MAX_SIZE_ 20
template <typename T>
Array <T>::Array (void)
:data_(new T[MAX_SIZE_]),
cur_size_(0),
max_size_(MAX_SIZE_)
{ }
template <typename T>
Array <T>::~Array (void)
{
delete[] this->data_;
this->data_ = nullptr;
}
Main.cpp:
#include "Array.h"
int main(void)
{
Array_Base<int>* arr = new Array<int>();
delete arr;
}
I keep getting an error that says: "a value type of "Array" cannot be used to initialize an entity of type "Array_Base" from a red line that appears under the "new" operator in main.
Any help would be greatly appreciated. Thank you!
template <typename T>
class Array : public Array_Base
Array_Base does not name a class. You need to provide it with a template argument.
Do you mean this?
template <typename T>
class Array : public Array_Base<T>
I want to separate .h and .cpp for template class.
Here is the what I was doing:
I wrote directly .h and .cpp like without template. So it creates an exception like Link 2019 Template exception
There are some solution to handle this How to define template class header and implement it in another cpp. I choose solution 3.
According to the solution I added include *.cpp just before #endif inside header.(Still *.cpp includes *.h)(Below code represents this step) It gives
template has already been defined error.
According to research the way of get rid of this error is(circular dependency) remove #include *.h from *.cpp but this time
unrecognizable template declaration/definition error
Occured. My question is if I include *.cpp to *.h file. How can we build project as expected? Or this solution is obsolute?
// TestTemp.h
#ifndef _TESTTEMP_H_
#define _TESTTEMP_H_
template<class T>
class TestTemp
{
public:
TestTemp();
void SetValue(T obj_i);
T Getalue();
private:
T m_Obj;
};
#include "TestTemp.cpp"
#endif
// TestTemp.cpp
#include "TestTemp.h"
template <class T>
TestTemp<T>::TestTemp()
{
}
template <class T>
void TestTemp<T>::SetValue(T obj_i)
{
}
template <class T>
T TestTemp<T>::Getalue()
{
return m_Obj;
}
#include "TestTemp.h"
int main()
{
TestTemp<int> a;
a.Getalue();
return 0;
}
Unlike member functions of ordinary classes, member functions of template classes cannot be compiled separately and linked into the executable. The members of a template must be visible to the compiler at the point where they're used. That's what all that nonsensical include stuff in that horrible article is about.
The simplest way to do this is to put the definitions directly into the template definition:
#ifndef TEST_H
#define TEST_H
template <class Ty>
class test {
public:
void f() { /* whatever */ }
};
#endif
This has the drawback that larger classes become unreadable (cf. Java). So the next step is to move the definitions outside the template, but keep them in the header:
#ifndef TEST_H
#define TEST_H
template <class Ty>
class test {
public:
void f();
};
template <class Ty>
void test<Ty>::f() { /* whatever */ }
#endif
Many people feel that that's still too cluttered, and want to put the definitions into a separate file. That's okay, too, but you have to make sure that that separate file gets included whenever the original header is used:
#ifndef TEST_H
#define TEST_H
template <class Ty>
class test {
public:
void f();
};
#include "test.imp"
#endif
This is the file "test.imp":
#ifndef TEST_IMP
#define TEST_IMP
template <class Ty>
void test<Ty>::f() { /* whatever */ }
#endif
Note that "test.imp" is really a header file, so it gets into your code through the #include "test.imp" directive in test.h. It cannot be compiled separately, so should not be named with a .cpp extension, which would, at best, be misleading.
I get linker errors when compiling the following code:
Here the header file:
// Solver.h
#ifndef SOLVER_H_
#define SOLVER_H_
#include <vector>
#include "Resource.h"
#include "ValueFunction.h"
template<typename T>
class Solver {
public:
Solver(std::vector<Resource>& resources);
private:
std::vector<T> valfuncs;
};
#endif /* SOLVER_H_ */
And here the source file:
// Solver.cpp
#include "Solver.h"
template<typename T>
Solver<T>::Solver(std::vector<Resource>& resources) :
valfuncs(resources.size()) {}
// Explicit class declaration
template class Solver<ValueFunction>;
And the call:
// openadp.cpp
#include "Solver.h"
int main(int argc, char *argv[]) {
std::vector<Resource> resources(4);
Solver<ValueFunction> sol(resources);
return 0;
}
The code is compiling fine if I remove valfuncs(resources.size()) from the initialization list. Why is it not possible to initialize the vector with the class passed from my template list?
Thanks in advance,
Reza
Update
Sorry, but this mini-example does not reproduce the error!
I'm trying to find one which does.
Update 2
The linker error was due to a wrong order of includes in my cmake files.
Remark
This question is not a duplicate of Why can templates only be implemented in the header file? first, because (the most obvious) the code compiles and second, there is an implicite instantiation of the Solver template: template class Solver<ValueFunction>;, thus the compiler is aware of an instance of the defined type.
I'm having trouble with compiling my template class. This is my list.cpp
using namespace std;
template <class T>
List<T>::List()
{
length = 0;
}
template <class T>
List<T>::~List()
{
}
template <class T>
List<T> & List<T>::operator=(const List<T> & rhs)
{
List<T> hha;
return hha;
}
template <class T>
int List<T>::size()
{
return length;
}
ANd this is my list.h
#ifndef _LIST_H_
#define _LIST_H_
#include <iterator>
#include <ostream>
using namespace std;
template <class T>
class List
{
private:
class ListNode
{
public:
ListNode();
ListNode(const T element);
ListNode *next;
T data;
};
public:
// big3
List();
~List();
List<T> & operator=(const List<T> & rhs);
int size();
bool empty();
void print(ostream & os) const;
private:
ListNode * head;
ListNode * tail;
int length;
};
#include "list.cpp"
#endif
when I run g++ list.cpp
I get errors
expected constructor, destructor, or type conversion before ‘<’ token
for definitions of constructor, destructor, and operator...
I don't know what seems to be wrong
The template implementation goes in the header.
It is a bit of a hack but it is how it is done.
The problem you currently encounter is that you list.cpp doesn't include you list.h: the compiler sees a couple of definitions for things which aren't declared, yet. You can fix this problem by including list.h at the top of your file:
#include "list.h"
...
However, this will essentially lead to a problem coming: if you actually want to use your List<T> with some type, the compiler will need to see the template definition where the class template is used. That is, typically you will implement your templates in the header file. The alterntaive is to implement templates in an implementation file and explicitly instantiating the types it is to be used with. This is quite reasonable for some templates but for something intended to be used for an unknown number of types this isn't practical.
BTW, you are using names which you are not allowed to touch: names starting with an underscore followed by a capital letter are reserved for the C++ implementation, i.e. the compiler and the standard library. Names using two consecutive underscores anywhere are also reserved.
Since list.hpp doesn't get #included in list.cpp, the compiler doesn't know about the template definition in that header when you try to compile list.cpp.
You compile list.cpp, that defines your list member functions. But it doesn't contain the template class declaration - that is in the header.
I see you include cpp in your list header. This will sort of work if you include the list header in some other cpp file and make sure list.cpp will not be compiled as a separate compilation unit.
What I mean is i.e. file main.cpp:
#include "list.h"
int main()
{}
Then compile this with g++ main.cpp.
Usually you just want to avoid cpp files when using templates altogether. Just stuff everything in the header and include that. Or alternatively I would at least rename your list.cpp to list.impl or some other name. This way one might be less tempted to actually try to compile that file directly.
I am trying to implement an observer pattern with a template subject class. The observers don't (need to) know the subjects type, so I made an interface for the attach method without this type. This is my implementation:
SubjectInterface.h
#ifndef SUBJECTINTERFACE_H_
#define SUBJECTINTERFACE_H_
#include <list>
#include "Observer.h"
// Template-independant interface for registering observers
class SubjectInterface
{
public:
virtual void Attach(Observer*) = 0;
}; // class SubjectInterface
#endif // SUBJECTINTERFACE_H_
Subject.h
#ifndef SUBJECT_H_
#define SUBJECT_H_
#include <list>
#include "Observer.h"
#include "SubjectInterface.h"
template <class T>
class Subject : public SubjectInterface
{
public:
Subject();
~Subject();
void Attach(Observer*);
private:
T mValue;
std::list<Observer*> mObservers;
}; // class Subject
#include "Subject.cpp"
#endif // SUBJECT_H_
Subject.cpp
template <class T>
Subject<T>::Subject()
{
}
template <class T>
Subject<T>::~Subject()
{
}
template <class T>
void Subject<T>::Attach(Observer* test)
{
mObservers.push_back(test);
}
Observer.h
#ifndef OBSERVER_H_
#define OBSERVER_H_
#include "SubjectInterface.h"
#include <iostream>
class Observer
{
public:
Observer(SubjectInterface* Master);
virtual ~Observer();
private:
SubjectInterface* mMaster;
}; // class Observer
#endif // OBSERVER_H_
Observer.cpp
#include "Observer.h" // include header file
Observer::Observer(SubjectInterface* Master)
{
Master->Attach(this);
}
Observer::~Observer()
{
}
When I compile this using the gcc 4.3.4, I get the following error message:
SubjectInterface.h:10: error: ‘Observer’ has not been declared
I don't understand this, because the Observer is included just a few lines above. When I change the pointer type from Observer* to int*, it compiles OK. I assume that there is a problem with the template subject and the non-template interface to it, but that is not what gcc is telling me and that doesn't seem to be the problem when using int*.
I searched for template/observer, but what I found (e.g. Implementing a Subject/Observer pattern with templates) is not quite what I need.
Can anyone tell me, what I did wrong or how I can call the templated attach-method from a non-template observer?
You have a circular include chain, SubjectInterface.h includes Observer.h which in turns includes SubjectInterface.h.
This means that the include guards will prevent Observer from being visible. To fix it instead forward declare Observer.
// SubjectInterface.h
#ifndef SUBJECTINTERFACE_H_
#define SUBJECTINTERFACE_H_
#include <list>
class Observer; //Forward declaration
// Template-independant interface for registering observers
class SubjectInterface
{
public:
virtual void Attach(Observer*) = 0;
}; // class SubjectInterface
#endif // SUBJECTINTERFACE_H_
You have a circular dependency; Observer.h includes SubjectInterface.h, and vice versa. You will need to break this with a forward declaration.