Template Type is undefined - c++

I'm learning C++ and now I'm working with Template.
I'm trying to implement a Linked List:
ListElement.hpp
#ifndef LIST_ELEMENT_HPP_
#define LIST_ELEMENT_HPP_
template <class Type> class SingleLinkedList;
template <class Type>
class ListElement
{
public:
ListElement(const Type element);
~ListElement(void);
public:
Type val;
ListElement* next;
};
#endif
ListElement.cpp:
#include "ListElement.hpp"
ListElement<Type>::ListElement(const Type element)
{
*next = NULL;
val = element;
}
ListElement<Type>::~ListElement(void)
{
}
I'm getting an Error on ListElement.cpp releated to Type: Type is undefined.
I have found a lot of examples about how to implement a Linked List but none using a separated hpp and cpp.
Do you know how can I fix this error?

First problem:
You need to fix the way you are defining the member functions of your class template:
template<typename Type> // <== ADD THIS!
ListElement<Type>::ListElement(const Type& element)
// ^
// And perhaps also this?
// (don't forget to modify the
// corresponding declaration if
// you change it)
{
*next = NULL;
val = element;
}
Second problem:
You should move those definitions to the same header file that contains the definition of the class template, or the linker will complain about undefined references. For more information, see this Q&A on StackOverflow.
Third problem:
In your constructor, you are currently causing undefined behavior by dereferencing an uninitialized pointer. You shouldn't be doing:
*next = NULL;
^^^^^^^^^^^^^
Undefined Behavior! next is uninitialized and you are dereferencing it!
But rather:
next = NULL;
Or even better (using constructor initialization lists and C++11's nullptr):
template<typename Type>
ListElement<Type>::ListElement(const Type& element) :
val(element),
next(nullptr)
{
}

Firstly - in general you cannot split declaration and implementation of template class in different files.
Secondly - before implementation should be template decl.
template<typename Type>
ListElement<Type>::ListElement(const Type element)
{
next = NULL;
val = element;
}

At first try to add
template<class Type>
before each function in .cpp file
It wouldn't work. (Linker errors) So move all your implementation to .h file.
Then perhaps you should change
ListElement(const Type element);
to
ListElement(const Type &element);

Related

using a template with a struct incomplete type error

#include <iostream>
#include <string>
#include <map>
using namespace std;
template<typename T>
struct Node
{
map<string, T> data;
struct Node* left, * right, * bottom;
Node(map<string, T> data)
{
this->data = data;
left = right = bottom = NULL;
}
};
int main()
{
cout << endl;
map <string, string> test;
test["walid"] = "walid";
struct Node* root = new Node(test); #error here
cout << root->data["walid"];
cout << endl;
return 0;
}
can someone please tell me why I'm getting incomplete type error? I'm trying to get the node to be created with different map value type depending on the data.
can someone please tell me why I'm getting incomplete type error?
Because you're attempting to create a pointer to a type that you haven't defined / attempting to create a dynamic object of type that you haven't defined.
You haven't defined a type called Node. You've defined a class template called Node. You cannot have a Node* for the same reason that you cannot have a std::vector*. This compiler error explains what is going on:
error: template argument required for 'struct Node'
You can instantiate the template to get a class, which is a type. The angle bracket syntax is used to instantiate templates, and to pass the template arguments. Example:
Node<std::string>* root = ...
Note that if you let the compiler to deduce the type of the pointer from the initialiser, then the compiler can implicitly deduce the class template arguments (this language feature was introduced in C++17):
auto* root = new Node(test);
P.S. Your example would leak memory if it compiled. Avoid bare owning pointers. Prefer RAII containers and smart pointers instead. Also avoid dynamic allocation when you don't need it.
Node is not a type, it's a template. Node<string> is the type you are after.
Also, struct in a variable declaration is redundant in C++, so change that line to:
Node<string>* root = new Node<string>(test);
Don't forget to delete root; later -- or you could just make root a value:
Node<string> root{test};
Finally, you can optimize several things here with std::move, such as:
Node(map<string, T> data)
{
this->data = data;
left = right = bottom = NULL;
}
Using initializer lists and std::move you can save a possibly-expensive copy of data:
Node(map<string, T> d) :
data{std::move(d)},
left{nullptr}, right{nullptr}, bottom{nullptr} {}
Likewise, since you never use test again, you could move that into the constructor argument:
Node<string> root{std::move(test)};

C++ Templated linked list getting data element of a complex data type

I've been working on updating my old templated linked list to be able to take a complex data type. But I have no idea how to make it be able to return the data element in the node class. Currently the code for my node class looks like this:
using namespace std;
#ifndef Node_A
#define Node_A
template <class T>
class Node
{
public:
Node();
~Node();
T getData();
Node* getNext();
void setData(T);
void setNext(Node*);
private:
Node *next;
T data;
};
template <class T>
Node<T>::Node()
{
next = NULL;
return;
}
template <class T>
Node<T>::~Node()
{
return;
}
template <class T>
T Node<T>::getData()
{
return data;
}
template <class T>
Node<T>* Node<T>::getNext()
{
return next;
}
template <class T>
void Node<T>::setData(T a)
{
data = a;
return;
}
template <class T>
void Node<T>::setNext(Node* a)
{
next = a;
return;
}
#endif
Now this works perfectly fine if the data type T is a primitive but if you use a non-primitive like say a struct it would give a runtime error. I presume because structs don't do operator overloading for = operator. Is there a simple way of fixing this without completely overhauling the class?
It's not about overloading the = operator, it's about implementing the assignment operator for the struct. If you do that, you won't need to change your Node class, unless I've missed something else.
The above assumes that you'll be making copies of the data inside the Node. Alternatively, you can pass the data by reference. In this case, you need to be careful that the data doesn't get deleted before the Node object is deleted, otherwise you'll get a crash when trying to access a deleted data object from your Node.

Templates and access

I've read tons of guides of how to use templates effectively, however none seem to answer this question. They all seem to access the nodes inside the class and nothing more.
For example, I have a doubly linked list. The list contains a Node:
template<class T>
struct TNode
{
T Data;
TNode* pNext;
TNode* pPrev;
};
Now I'm trying to make the data accessible from anywhere, for example:
TNode* pNode = m_VertexList.GetFirstElement();
However every way I've tried, I end up having to cast it in some way:
TNode<CObject*>* pNode = m_VertexList.GetFirstElement<CObject*>();
//I can't remember at this point if this is the exact syntax, but you get the idea
Now while this isnt a very big problem, it isn't ideal
Is there a way I can make it so the first line will correctly return the type without having to specify it?
Here is the error I get:
1>...error C2955: 'TNode' : use of class template requires template argument list
Here in pastebin is the whole node structure and dllist class:
http://pastebin.com/awkq9rcq
Any help would be appreciated :)
You would need something like auto node = m_VertexList.GetFirstElement(); because m_VertexList should be a class template. But you can add a typedef for the node to the list class and use that too:
template <typename T>
struct List
{
typedef Node<T> node_type;
typedef Node<T>* node_ptr_type;
node_ptr_type GetFirstElement() { return first_; }
node_ptr_type first_;
....
};
then
typedef List<Cobject> CObjectList
CObjectList l;
auto n0 = l.GetFirstElement();
CObjectList::node_ptr_type n1= l.GetFirstElement();
Once you're done with this exercise, you may want to look at std::list for an example of a well implemented doubly linked list class template.

C++ Invalid use of member function, did you forget the ( )?

I'm working on an assignment where I create my own container using templates. The container I am required to use is called Smaph, which takes in two pairs of numbers and does a variety of functions with them. I am only allowed to make a header file for this assignment. I've created a singly-linked class slink, that takes one template argument.
Currently, I am trying to get a feel for templates and learning how to use them, so I have a very simple example I was hoping you could help me with. I have a push_back function in my singly linked list class to add to my templates. For some reason, I can't add things to my slink because I get a compile time error that says, Invalid use of member function, (push_back), did you forget the ( )? Can someone explain to me why I am getting this error?
Thank you!
template <typename T>
class slink {
private:
struct node {
T datum;
struct node *next;
};
node *head, *tail;
public:
slink() : head(0), tail(0) {
}
~slink() {
clear();
}
void push_back(const T &datum) {
node *p = new node;
p->datum = datum;
p->next = 0;
if (!tail)
head = p;
else
tail->next = p;
tail = p;
}
template <typename Tfirst, typename Tsecond>
class Smaph {
public:
Smaph();
~Smaph();
Smaph(const Tfirst a, const Tsecond b) {
std::pair<Tfirst, Tsecond> pair1(a, b);
s.push_back(pair1);
}
private:
slink<std::pair<Tfirst, Tsecond> > s();
};
And finally, my main to test my program. All I want to do right now is add these two numbers to my singly linked list through my Smaph.
int main() {
Smaph<int, double> s(3, 6.3);
}
slink<std::pair<Tfirst, Tsecond> > s();
This is a declaration of a function called s that takes no arguments and returns a slink<std::pair<Tfirst, Tsecond> >. When the compiler sees you do s.push_back(pair1);, it wonders what you're trying to do to that poor function. Remove the () to make it a data member:
slink<std::pair<Tfirst, Tsecond> > s;
On this line you did:
slink<std::pair<Tfirst, Tsecond> > s();
This is declaring a function named s that returns slink<std::pair<Tfirst, Tsecond> >. But then you did this inside one of your member functions:
s.push_back(pair1);
That isn't right, which is why your compiler alerts you of invalid use of this member function.
To fix, remove the parameters:
slink<std::pair<Tfirst, Tsecond> > s;

Template Class Linked List Insertion Error

When I attempt to insert this 'food' object into my template class linked list 'test'. I get this error:
request for member ‘addNode’ in ‘test’, which is of non-class type ‘Catalog<FoodSource>()
Here's my coding, What am I doing wrong?
##main:##
int main(void)
{
Catalog<FoodSource> test();
FoodSource food();
test.addNode(const &food);
return(0);
}
##function definition in .h:##
template<class T>
class Catalog
{
public:
void addNode(const T& value);
};
##function implementation in .cpp:##
template <class T>
void Catalog<T>::addNode(const T& value)
{
Node *temp;
if(head == NULL)
head = new Node (value, NULL);
else
{
temp=head;
while(temp->next !=NULL)
temp=temp->next;
temp->next = new Node (value, NULL);
}
}
You just found one of the many warts present in the C++ syntax. The standard requires that if an expression can be interpreted both as a declaration and as a definition then it must be considered as a declaration. For example your code
Catalog<FoodSource> test();
is not defining a variable named test but is instead declaring that there is a function named test that takes no arguments and that returns a Catalog<FoodSource> instance.
To define the variable you need to omit the parenthesis.
Note that there are cases where this trap is much harder to notice... for example:
double x = 3.14159;
int y(int(x));
as surprising it may seem in the above code y is declared as a function!
Declaration and implementation of a class template should be in the same file.
Also, you can just call test.addNode(food); in main.
Given definition for all the classes Node, FoodSource etc is available, you need to do at least the following:
1) Move the function definition to .h file
2) The first line in main function is ambigous. It should be rewritten as Catalog<FoodSource> test; because Catalog<FoodSource> test() will be treated as function prototype