am i implementing this template class correctly? - c++

Okay, I'm trying to implement a templated class of an array-based queue called Queue.
Here's how I did it. First, is this the right way to implement a templated class?
The problem is, when I try to compile, I get the error messages
undefined reference to
'Queue::Queue()'
undefined reference to
'Queue::~Queue()'
Any ideas what's wrong? Am I declaring it wrong or implementing it wrong?
queue.h
#ifndef __QUEUE_H__
#define __QUEUE_H__
template <class T>
class Queue
{
int first;
T* array;
public:
Queue();
~Queue;
void enqueue(T next);
T dequeue();
bool is_empty();
bool is_full();
};
#endif
queue.cpp
#include "queue.h"
template <class T> Queue<T>::Queue(){
...
}
template <class T> Queue<T>::~Queue(){
...
}
template <class T> void Queue<T>::enqueue(T next){
...
}
template <class T> T Queue<T>::dequeue(){
...
}
template <class T> bool Queue<T>::is_empty(){
...
}
template <class T> bool Queue<T>::is_full(){
...
}
main.cpp
#include "queue.h"
#include <iostream>
using namespace std;
int main(){
Queue<int> test;
return 0;
}

Several issues:
The cause of your problem - C++ does not really support splitting templates into .h and .cpp files - you need to put everything in the header
The name __QUEUE_H__ is reserved for the C++ implementation, as are all names that contain double-underscores or begin with an underscore and an uppercase letter. You are not allowed to create such names in your own code.
You probably will find it more convenient to implement the queue in terms of a std::deque, rather than a C-style array
I assume you are doing this as a learning exercise, but if not you should know that the C++ Standard Library already contains a std::queue template class.

A template is really just a fancy form of macro that the compiler is aware of, for nearly every implementation of C++. The definitions have to be present so that the compiler can generate code in place of the template.

Related

Avoiding duplicate code in C++ template implementation

I split a generic class into a header and implementation file as follows.
Test.h:
#ifndef MY_DESCRIPTIVE_GUARD_NAME
#define MY_DESCRIPTIVE_GUARD_NAME
template<typename T>
class MyClass
{
T myObj;
public:
MyClass(T& obj);
void set(T& obj);
T get();
}
#include "Test.tpp"
#endif
Test.tpp:
template<typename T>
MyClass<T>::MyClass(T& obj) {
// implementation
}
// etc.
But as I add more methods to MyClass, I keep having to write the same boilerplate:
template<typename T> return-type MyClass<T>::method_name
With dozens of methods (not to mention if I include more template parameters), I'm writing a lot of repeated code. Should I use a macro? Suck it up? Or is there a feature in the language that allows me to package multiple method implementations in one unit, almost as if they were defined in the header file?

C++ template: <class> does not name a type

Newbie to C++ so please forgive me. I'm trying to write a simple template class to implement the Stack data structure functionality. I've read through this question to understand how template declaration and implementation works: Why can templates only be implemented in the header file?. But I would like to use the solution where class declaration and implementation are separate (not defined inline in .h).
MyStack.h:
#include "StackNode.h"
#include "MyStack.tpp"
template <typename T>
class MyStack
{
private:
StackNode<T> *top;
public:
MyStack();
virtual ~MyStack();
};
MyStack.tpp:
#include "MyStack.h"
template <typename T>
MyStack<T>::MyStack()
: top(nullptr)
{
}
template <typename T>
MyStack<T>::~MyStack()
{
}
main.cpp:
#include "MyStack.h"
int main() {
MyStack<int> myStack;
return 0;
}
However compiling the above gives this error:
../src/MyStack.tpp:11:1: error: 'MyStack' does not name a type
../src/MyStack.tpp:18:1: error: 'MyStack' does not name a type
I know I'm missing something, but don't understand what. Thanks!
The problem is that you are including the .tpp file, which contains the class method definitions, before the class has actually been declared yet. You need to move that #include statement below the class declaration instead.
Also, the .tpp file should not be #include'ing the .h file that originally #include'd it. In fact, that won't work correctly since your .h file is missing header guards to prevent multiple inclusions within the same translation unit (ie, main.cpp in this case). So, you would end up with MyStack.h which includes MyStack.tpp which includes MyStack.h again, which causes an error when it tries to re-declare things that are already declared. Always declare a header guard in your .h files.
Try this instead:
MyStack.h:
#ifndef MyStack_H
#define MyStack_H
#include "StackNode.h"
template <typename T>
class MyStack
{
private:
StackNode<T> *top;
public:
MyStack();
virtual ~MyStack();
};
#include "MyStack.tpp"
#endif
MyStack.tpp:
template <typename T>
MyStack<T>::MyStack()
: top(nullptr)
{
}
template <typename T>
MyStack<T>::~MyStack()
{
}

How to properly use Templates?

I am trying to create a vector class that looks something like this:
template <typename T>
class Vector
{
.
.
.
};
#include "vector.cpp"
However, when I start writing my functions in "vector.cpp", CLion complains that I have duplicate functions. How do I work around this? I believe in NetBeans, I can add vector.h & vector.cpp to a folder called "Important Files" which would fix the problem. I am not sure what the equivalent in CLion is.
General Design of a template
example.h
#ifndef EXAMPLE_H
#define EXAMPLE_H
// Needed includes if any
// Prototypes or Class Declarations if any
template<class T> // or template<typename T>
class Example {
private:
T item_;
public:
explicit Example( T item );
~Example();
T getItem() const;
};
#include "Example.inl"
#endif // EXAMPLE_H
Example.inl
// Class Constructors & Member Function implementations
template<class T>
Example<T>::Example( T item ) : item_(item) {
}
template<class T>
Example<T>::~Example() {
}
template<class T>
T Example<T>::getItem() const {
return item_;
}
Example.cpp
#include "Example.h"
// Only need to have the include here unless if
// the class is non template or stand alone functions
// are non-template type. Then they would go here.

encapsulation and friend classes in C++

I'm studying C++ container and iterators and I'm trying to implement a rudimental linked list, just to get the hang of thi inner workings of iterators and container related stuff.
I defined a node class, along with a list class and the associated iterator, every class in its own header file,and each header is implemented in a separated code file.I didn't care about friend declarations,that was something I intended to cater to while trying to compile the project, but I stumbled upon something I failed to understand.
I defined several private fields in each class,and I expected the compiler to throw some errors at me during compilation, but it seems to be just fine with that! can you explain where am I wrong?? here's the code:
the node class:
template <typename T>
class mylist_node {
public:
mylist_node(const T&,mylist_node<T>*);
~mylist_node() {}
private:
T element;
mylist_node<T> *next;
};
the list class:
template <typename T>
class mylist {
public:
typedef mylist_iterator<T> iterator;
mylist() : head(NULL),tail(NULL) {}
void push_back(const T&);
bool empty();
iterator begin();
iterator end();
private:
mylist_node<T> *head,*tail;
};
the list implementation code:
#include <cstdlib>
#include "mylist_node.h"
#include "mylist_iterator.h"
#include "mylist.h"
template <typename T>
void mylist<T>::push_back(const T& element)
{
//dynamically allocated object so it is not destroyed on function exit
mylist_node<T> *new_node=new mylist_node<T>(element,NULL);
if (head==NULL)
head=new_node;
else
tail->next=new_node;
tail=new_node;
}
template <typename T>
bool mylist<T>::empty()
{
return head==tail;
}
template <typename T>
typename mylist<T>::iterator mylist<T>::begin()
{
return mylist_iterator<T>(head);
}
template <typename T>
typename mylist<T>::iterator mylist<T>::end()
{
return mylist_iterator<T>(NULL);
}
and the iterator class:
template <typename T>
class mylist_iterator {
public:
T &operator*();
const mylist_iterator<T> &operator++();
bool operator!=(const mylist_iterator<T>&);
private:
mylist_iterator(mylist_node<T> *pointee) : pointee(pointee) {}
mylist_node<T> *pointee;
};
obiouvsly the mylist<T>::push_back() and the overloaded operators in mylist_iterator all access the private fields in mylist_node.
I separatedly compile the source files without the compiler complaining about anything at all!
There must be something I didn't fully understand..
thanks!
Compilers typically don't have a way to "sort of" compile code to figure out errors that would occur regardless of the type. They need to actually compile the code with a real type to detect most errors. If you never instantiate any of these classes, the real compilation won't take place.

c++ how to do to deal with circular dependencies?

usually, if my #include chain gets circular, I solve it by replacing one of the #includes by a forward declaration and then move all the function implementations that depend on this type into the cpp file, where I #include the header instead.
But - in some situations it's bad to put function implementation into the cpp file - especially when dealing with templates or for inline functions.
Therefore - Are there other ways to deal with circular #include chains rather than using forward declarations?
thanks!
You should limit such circular dependencies because they make code difficult to understand and hard to work with.
That said, sometimes such dependencies are necessary. In those cases, you can declare all of the entities in a single header file, then after all of the declarations provided definitions for any function templates and inline functions. For example:
#ifndef MY_AWESOME_INCLUDE_GUARD
#define MY_AWESOME_INCLUDE_GUARD
template <typename> struct B;
template <typename T>
struct A
{
template <typename U>
void f(B<U>);
};
template <typename T>
struct B
{
template <typename U>
void f(A<U>);
};
template <typename T>
template <typename U>
void A<T>::f(B<U>) { }
template <typename T>
template <typename U>
void B<T>::f(A<U>) { }
#endif