I want to make a template class and pass it a compare function. I found a great answer on this link
Unfortunately when I made a template class called "WaitingQueue" and passed the compare function in the constructor of the class(in class foo), the code does not compile and throws error: "'compare' is not a type".
I cannot understand the error here. The code in the link above runs without error. Can anyone please tell me what I have done wrong here? Thanks in advance
#include <stdint.h>
#include <stddef.h>
#include <string.h>
enum { OK, ERROR };
template <class T>
class WaitingQueue
{
struct QueueElement
{
public:
T data;
QueueElement *next;
QueueElement(T *pdata): next(0)
{
memcpy(&data, pdata, sizeof(T));
}
};
QueueElement *head, tail;
public:
bool (*comparefunc)(uint16_t, T*);
WaitingQueue (bool (*compareFunction)(uint16_t, T*)) :comparefunc(compareFunction), head(0), tail(0) { }
int search(int16_t id, T *ret_data)
{
QueueElement *temp = head;
QueueElement *prev = 0;
if (temp != NULL)
{
if (comparefunc(id, &temp->data) == true)
{
if (prev)
{
prev->next = temp->next;
}
else
{
head = head->next;
}
memcpy(ret_data, &temp->data, sizeof(temp->data));
delete temp;
return OK;
}
prev = temp;
temp = temp->next;
}
return ERROR;
}
};
typedef struct _cmd
{
uint8_t flags;
uint16_t id;
} cmd;
bool compare(uint16_t id, cmd *cmd)
{
return (cmd->id == id);
}
class foo
{
WaitingQueue<cmd> queue(compare);
};
This is the usual vexing parse. WorkingQueue<cmd> queue(compare); is understood by the compiler as the declaration of a method named queue returning a WorkingQueue<cmd> and taking an object of the nonexistant type compare. You can make it understand that you mean to declare a field initialized with the compare function by using braces initialization:
WaitingQueue<cmd> queue{compare};
Related
I am trying to make a Generic Linked list in C++ using templates. But i am getting this error 'GenericNode::{ctor}': constructors not allowed a return type through which i can't possibly know what am i doing wrong?
PS. i have also gone through other posts here on Stack Overflow which says that the error is due to the missing semi-colon after the class definition but i think i don't have a 'missing semi-colon' case. Any help?
Code :
GenericLinkedList.h :
#pragma once
template <typename Datatype>
class GenericNode {
Datatype T;
GenericNode *next;
public:
GenericNode() {}
GenericNode(Datatype T);
};
template<typename Datatype>
void GenericNode<Datatype>::GenericNode(Datatype data) {
T = data;
}
template <typename Datatype>
class GenericLinkedList {
GenericNode *Data;
public:
GenericLinkedList() {
Data = NULL;
}
int isEmpty();
void addDataAtFront(Datatype data);
void addDataAtEnd(Datatype data);
void print();
};
template <typename Datatype>
int GenericLinkedList<Datatype>::isEmpty() {
return Data == NULL;
}
template <typename Datatype>
void GenericLinkedList<Datatype>::addDataAtFront(Datatype data) {
GenericNode *newNode, *tmpNode;
newNode = new Node;
newNode->T = data;
newNode->next = NULL;
if (Data == NULL) {
Data = newNode;
}
else {
tmpNode = Data;
Data = newNode;
Data->next = tmpNode;
}
}
template <typename Datatype>
void GenericLinkedList<Datatype>::addDataAtEnd(Datatype data) {
GenericNode *newNode, *tmpNode;
newNode = new Node;
newNode->T = data;
newNode->next = NULL;
if (Data == NULL) {
Data = newNode;
}
else {
tmpNode = Data;
while (tmpNode->next != NULL) {
tmpNode = tmpNode->next;
}
tmpNode->next = newNode;
}
}
template <typename Datatype>
void GenericLinkedList<Datatype>::print() {
GenericNode tmpNode;
tmpNode = Data;
for (tmpNode;tmpNode != NULL;tmpNode = tmpNode->next) {
cout << tmpNode->T << " ";
}
}
.cpp :
#include <iostream>
#include <conio.h>
#include "GenericLinkedList.h"
using namespace std;
int main() {
GenericLinkedList<int> T;
T.addDataAtFront(5);
T.addDataAtEnd(6);
T.addDataAtFront(4);
T.print();
_getch();
}
template<typename Datatype>
void GenericNode<Datatype>::GenericNode(Datatype data) {
T = data;
}
You write the return type void. It's a constructor.
void GenericNode::GenericNode(Datatype data)
remove void its a constructor. Constructors don't return and dont have a return type.
I am trying to write a exception safe generic stack. This is what I have done so far.
#include <iostream>
#include <memory>
#include <exception>
class stk_exception:public exception
{
virtual const char* what() const throw()
{
return "stack underflow";
}
} stk_ex;
template <class T>
struct node
{
T data;
node<T> *next;
};
template <class T>
class stack_generic
{
public:
stack_generic() : _head(nullptr) {
}
void push(T x) {
node<T> *temp(new node<T>());
temp->data = x;
temp->next = _head;
_head = temp;
}
void pop() {
if (_head == nullptr) {
throw stk_ex;
} else {
node<T> *temp = _head;
_head = _head->next;
delete temp;
return;
}
}
T top() {
T x = T();
if (_head == nullptr) {
throw stk_ex;
} else {
return _head->data;
}
}
private:
node<T> *_head;
};
int main()
{
stack_generic<int> s;
s.push(1);
s.push(2);
std::cout << s.top();
s.pop();
std::cout << s.top();
s.pop();
}
I could have used STL list/vector for RAII, but I want to work with raw pointers. So, when I wrap the head pointer in stack with unique_ptr, it throws a compilation error "no matching function for call unique_ptr, default_delete. What's wrong here? Can anyone suggest what should I do to make this class exception safe? Thanks!
EDIT:
Added exception handling for underflow.
defined seperate top and pop methods
The following implementation should be (almost) exception-safe:
void push(T x) {
head = new node<T>{std::move(x), head};
}
T pop(void) {
if (head) {
T result{std::move(head->data)};
auto old = head;
head = head->next;
delete old;
return result;
} else {
cout << "underflow!";
return T{};
}
}
The only problem of this code is the return result. In general, this operation might throw an exception, and in this case, the caller sees an exception, but the stack was nevertheless changed.
You can avoid this problem by separating the function into two functions. The first function returns the top element, and the second function removes it.
Best practice is to use the std::shared_ptr. You could implement the class like this:
#include <iostream>
#include <memory>
#include <exception>
template <class T>
class node
{
public:
node(T data, std::shared_ptr<node<T>> next)
: _data(data), _next(next)
{
}
T data() const
{
return _data;
}
std::shared_ptr<node<T>> next() const
{
return _next;
}
private:
T _data;
std::shared_ptr<node<T>> _next;
};
template <class T>
class stack_generic
{
public:
stack_generic()
: _head(nullptr)
{
}
void push(T x)
{
_head = std::make_shared<node<T>>(x, _head);
}
T pop()
{
if (_head == nullptr) {
throw std::underflow_error("underflow");
} else {
std::shared_ptr<node<T>> temp = _head;
_head = _head->next();
return temp->data();
}
}
private:
std::shared_ptr<node<T>> _head;
};
int main()
{
stack_generic<int> s;
s.push(1);
s.push(2);
std::cout << s.pop();
std::cout << s.pop();
}
Note the following things:
Using of using namespace std; is bad practice.
Use nullptr instead of NULL for modern C++ programs.
Use an exception for the underflow to create a defined behaviour.
Use accessor methods on the node to create a read-only object.
Use a constructor for the node.
Using for example std::shared_ptr to automatically free data.
i made this linked list class in c++ and it works fine except after i run it the program goes unresponsive. i have located the line that's causing the problem but i have no idea why. Even when i type it differently it still does the same thing.
Here's my list class:
#include <string>
template<class T>
class List : public Object{
private:
Node<T>* first;
Node<T>* last;
int length;
public:
List() : Object(new std::string("List")) {
first = NULL;
last = NULL;
length = 0;
}
~List() {
delete first;
delete last;
}
void Add(T value) {
if(first==NULL)
first = new Node<T>(NULL, value);
else if(last==NULL)
---->last = new Node<T>(first, value);<-----
else
last = new Node<T>(last, value);
length++;
}
T Remove(T value) {
Node<T>* temp = first;
while(temp!=NULL) {
if(temp->GetValue()==value) {
temp->GetPrev()->SetNext(temp->GetNext());
temp->GetNext()->SetPrev(temp->GetPrev());
delete temp;
length--;
return value;
}
temp = temp->GetNext();
}
return 0;
}
T Get(int index) {
Node<T>* temp = first;
int i = 0;
while(temp!=NULL) {
if(i==index)
return temp->GetValue();
i++;
temp = temp->GetNext();
}
return 0;
}
};
when i remove the marked line above the program go unresponsive. This is my Node constructor:
#include <string>
template<class T>
class Node : public Object{
private:
Node* next;
Node* prev;
T value;
public:
Node(Node* prev, T value) : Object(new std::string("Node")){
if(prev!=NULL) {
prev->next = this;
this->prev = next;
}
next = NULL;
this->value = value;
}
~Node() {
delete next;
}
T GetValue() {
return value;
}
Node* GetNext() {
return next;
}
Node* GetPrev() {
return next;
}
};
my object class:
#include <string>
class Object {
private:
std::string* type;
public:
Object() {
type = new std::string("Object");
}
Object(std::string* type) {
this->type = type;
}
~Object() {
delete type;
}
std::string* GetType() {
return type;
}
};
my Test.cpp
#include <iostream>
#include <string>
#include "Object.h"
#include "Node.h"
#include "List.h"
using namespace std;
int main () {
List<int> l;
l.Add(5);
l.Add(93);
l.Add(17);
l.Add(7789);
l.Add(60);
cout << "node 4 is:" << l.Get(3) << endl;
return 0;
}
error image http://i50.tinypic.com/2mw5phi.png
thanks for reading and please help as soon as you can, comment if you need me to supply more info.
Edit: There are many problems with your program, but what might be causing your crash: Your Add-function does not work correctly. It should be something like this:
if(first==NULL) {
first = new Node<T>(NULL, value);
last = first;
} else {
last = new Node<T>(last, value);
}
length++;
Otherwise, it will not correctly insert the second element. Why? With your original code, after the first add, your last is still NULL because of the else. So on the second add, you set last to new Node<T>(NULL, value). Therefore, it will not assign the first element's next pointer. And your list will be inconsistent.
Apart from that, there are double-frees, unnecessary heap-allocation of the string field in your Object class, ownership issues etc. To give you just one more example: Your List destructor will cause a heap corruption due to a double free. Calling delete first will delete all nodes due to the delete next in Node's destructor, as long as the list is consistent. Then you call delete last, but that object was already freed. This will corrupt your program's memory management and can also cause a crash at program exit.
Does this function seem correct to you??
It says GetPrev, but its actually getting next.
Node* GetPrev() {
return next;
}
I found that if I comment out this line in the Node constructor the code compiles:
if (next != NULL) {
// next->next = this;
prev = next;
}
Edit 1:
I also realized that you were doing this in your Node class:
private:
Node* next;
Node* prev;
T value;
Since these objects are declared in the Node class, they are at this time incomplete types. I managed to replicate that problem down to a simple one like this:
template <class T>
struct S {
S* s = new S();
~S() { delete s; }
};
int main() {
S<int> s; // Segmentation fault (core dumped) ./test > .stdout
}
This causes a crash because S is an incomplete type within itself.
I'm getting the same segementation fault as I got in your code. I'm pretty sure it's because the pointers in the Node class are built upon incomplete types; and accessing the data from them is looking into memory that isn't yours, hence the crash.
I have three files and I want to compile and run them, but I keep getting some errors and warnings. Redefinition of struct Node< T >. I don't know much about templates, but this looks right to me. And, I spent a lot of time trying to figure out whats wrong. Thanks.
//mystack.h
#ifndef MYSTACK_H
#define MYSTACK_H
template <class T>
struct Node
{
T info;
T *next;
};
template <class T>
class MyStack
{
private:
struct Node<T> *top;
public:
void Push(T item);
void Pop();
int Top();
void Print();
};
#endif
//mystack.cpp
#include <iostream>
#include "mystack.h"
template <class T>
struct Node
{
T info;
T* next;
};
template <class T>
class MyStack
{
private:
struct Node<T>* top;
public:
void Push(T item)
{
if(top == NULL)
{
top = new( struct Node<T> );
top->info = item;
top->next = NULL;
} else
{
Node<T>* temp;
temp = top;
top = new( struct Node<T> );
top->info = item;
top->next = temp;
}
}
void Pop()
{
if( top == NULL )
{
} else
{
Node<T>* temp;
temp = top->next;
delete top;
top = temp;
}
}
int Top()
{
return top;
}
void Print()
{
if(top != NULL)
{
Node<T>* temp;
temp = top;
while(temp != NULL)
{
std::cout << temp << std::endl;
temp = temp->next;
}
}
}
};
One mistake you did in the listings is that you redefine this structure as it says.
Thats the definition:
template <class T>
struct Node
{
T info;
T* next;
};
This definition is done in both listings.
Edit: The second thing is that your class method implementation does not look right. You will have the most success if you try not to split cpp and header files while using templates.
If you were designing a class instead of a template, what you're doing would be wrong because you're redefining types.
But since you're writing templates, you're wrong earlier than that: you can't separately compile templates.
Brief pointer on the C++ compilation model:
// Definition of Node
template<typename T>
struct Node {
T info;
T* next; // shouldn't that be a Node*?
};
// Definition of MyStack
template <typename T>
class MyStack
{
private:
Node<T> *top;
public:
// Declarations, but not definitions, of the Mystack function members.
void Push(T item);
void Pop();
int Top();
void Print();
};
// Example definition of MyStack::Push
template<typename T>
void
MyStack<T>::Push(T item)
{
// as before
}
The type definitions usually appear in headers (if they are to be reused in different TUs) with include guards as you are doing. The guards are here because the definitions must appear at most once per TU. Do not manually repeat a type definition (e.g. in a source file as you did). This is wrong as it should be: nobody wants copy-n-paste errors.
The function members definitions usually appear in source files, unless they are the members of a template. In the latter case it's simpler to put them in headers (they don't have to be inline either).
You can learn the details of the compilation model elsewhere on SO, or in books, or on the Internet. Searching for 'template definition' or 'one definition rule' (or ODR) can help.
First, In header, remove 'struct' from the line 'struct Node *top;'. In C++ structs are almost identical to classes, the only difference being that struct members are public by default and class members are private by default. You do not need to preface struct types with the struct keyword like in straight C.
Second, Your CPP is all wrong. Templates are instantiated by the compiler when needed, so they do not live in CPP files to be compiled into objects like normal (apart from template specializations). You can put your template definitions in the HPP itself or a better general solution is to use an IPP file, i.e
// mystack.ipp
#ifndef MYSTACK_IPP
#define MYSTACK_IPP
#include "mystack.h"
#include <iostream>
template <class T>
void MyStack<T>::Push(T item)
{
if(top == NULL)
{
top = new( struct Node<T> );
top->info = item;
top->next = NULL;
} else
{
Node<T>* temp;
temp = top;
top = new( struct Node<T> );
top->info = item;
top->next = temp;
}
}
template <class T>
void MyStack<T>::Pop()
{
if( top == NULL )
{
} else
{
Node<T>* temp;
temp = top->next;
delete top;
top = temp;
}
}
template <class T>
int MyStack<T>::Top()
{
return top;
}
template <class T>
void MyStack<T>::Print()
{
if(top != NULL)
{
Node<T>* temp;
temp = top;
while(temp != NULL)
{
std::cout << temp << std::endl;
temp = temp->next;
}
}
}
#endif
Then '#include "mystack.ipp"' in any file which makes use of the implementation of MyStack
EDIT -- Answered below, missed the angled braces. Thanks all.
I have been attempting to write a rudimentary singly linked list, which I can use in other programs. I wish it to be able to work with built-in and user defined types, meaning it must be templated.
Due to this my node must also be templated, as I do not know the information it is going to store. I have written a node class as follows -
template <class T> class Node
{
T data; //the object information
Node* next; //pointer to the next node element
public:
//Methods omitted for brevity
};
My linked list class is implemented in a seperate class, and needs to instantiate a node when adding new nodes to the end of the list. I have implemented this as follows -
#include <iostream>
#include "Node.h"
using namespace std;
template <class T> class CustomLinkedList
{
Node<T> *head, *tail;
public:
CustomLinkedList()
{
head = NULL;
tail = NULL;
}
~CustomLinkedList()
{
}
//Method adds info to the end of the list
void add(T info)
{
if(head == NULL) //if our list is currently empty
{
head = new Node<T>; //Create new node of type T
head->setData(info);
tail = head;
}
else //if not empty add to the end and move the tail
{
Node* temp = new Node<T>;
temp->setData(info);
temp->setNextNull();
tail->setNext(temp);
tail = tail->getNext();
}
}
//print method omitted
};
I have set up a driver/test class as follows -
#include "CustomLinkedList.h"
using namespace std;
int main()
{
CustomLinkedList<int> firstList;
firstList.add(32);
firstList.printlist();
//Pause the program until input is received
int i;
cin >> i;
return 0;
}
I get an error upon compilation however - error C2955: 'Node' : use of class template requires template argument list - which points me to the following line of code in my add method -
Node* temp = new Node<T>;
I do not understand why this has no information about the type, since it was passed to linked list when created in my driver class. What should I be doing to pass the type information to Node?
Should I create a private node struct instead of a seperate class, and combine the methods of both classes in one file? I'm not certain this would overcome the problem, but I think it might. I would rather have seperate classes if possible though.
Thanks, Andrew.
While the answers have already been provided, I think I'll add my grain of salt.
When designing templates class, it is a good idea not to repeat the template arguments just about everywhere, just in case you wish to (one day) change a particular detail. In general, this is done by using typedefs.
template <class T>
class Node
{
public:
// bunch of types
typedef T value_type;
typedef T& reference_type;
typedef T const& const_reference_type;
typedef T* pointer_type;
typedef T const* const_pointer_type;
// From now on, T should never appear
private:
value_type m_value;
Node* m_next;
};
template <class T>
class List
{
// private, no need to expose implementation
typedef Node<T> node_type;
// From now on, T should never appear
typedef node_type* node_pointer;
public:
typedef typename node_type::value_type value_type;
typedef typename node_type::reference_type reference_type;
typedef typename node_type::const_reference_type const_reference_type;
// ...
void add(value_type info);
private:
node_pointer m_head, m_tail;
};
It is also better to define the methods outside of the class declaration, makes it is easier to read the interface.
template <class T>
void List<T>::add(value_type info)
{
if(head == NULL) //if our list is currently empty
{
head = new node_type;
head->setData(info);
tail = head;
}
else //if not empty add to the end and move the tail
{
Node* temp = new node_type;
temp->setData(info);
temp->setNextNull();
tail->setNext(temp);
tail = tail->getNext();
}
}
Now, a couple of remarks:
it would be more user friendly if List<T>::add was returning an iterator to the newly added objects, like insert methods do in the STL (and you could rename it insert too)
in the implementation of List<T>::add you assign memory to temp then perform a bunch of operations, if any throws, you have leaked memory
the setNextNull call should not be necessary: the constructor of Node should initialize all the data member to meaningfull values, included m_next
So here is a revised version:
template <class T>
Node<T>::Node(value_type info): m_value(info), m_next(NULL) {}
template <class T>
typename List<T>::iterator insert(value_type info)
{
if (m_head == NULL)
{
m_head = new node_type(info);
m_tail = m_head;
return iterator(m_tail);
}
else
{
m_tail.setNext(new node_type(info));
node_pointer temp = m_tail;
m_tail = temp.getNext();
return iterator(temp);
}
}
Note how the simple fact of using a proper constructor improves our exception safety: if ever anything throw during the constructor, new is required not to allocate any memory, thus nothing is leaked and we have not performed any operation yet. Our List<T>::insert method is now resilient.
Final question:
Usual insert methods of single linked lists insert at the beginning, because it's easier:
template <class T>
typename List<T>::iterator insert(value_type info)
{
m_head = new node_type(info, m_head); // if this throws, m_head is left unmodified
return iterator(m_head);
}
Are you sure you want to go with an insert at the end ? or did you do it this way because of the push_back method on traditional vectors and lists ?
Might wanna try
Node<T>* temp = new Node<T>;
Also, to get hints on how to design the list, you can of course look at std::list, although it can be a bit daunting at times.
You need:
Node<T> *temp = new Node<T>;
Might be worth a typedef NodeType = Node<T> in the CustomLinkedList class to prevent this problem from cropping up again.
That line should read
Node<T>* temp = new Node<T>;
Same for the next pointer in the Node class.
As said, the solution is
Node<T>* temp = new Node<T>;
... because Node itself is not a type, Node<T> is.
And you will need to specify the template parameter for the Node *temp in printlist also.
// file: main.cc
#include "linkedlist.h"
int main(int argc, char *argv[]) {
LinkedList<int> list;
for(int i = 1; i < 10; i++) list.add(i);
list.print();
}
// file: node.h
#ifndef _NODE_H
#define _NODE_H
template<typename T> class LinkedList;
template<typename T>class Node {
friend class LinkedList<T>;
public:
Node(T data = 0, Node<T> *next = 0)
: data(data), next(next)
{ /* vacio */ }
private:
T data;
Node<T> *next;
};
#endif//_NODE_H
// file: linkedlist.h
#ifndef _LINKEDLIST_H
#define _LINKEDLIST_H
#include <iostream>
using namespace std;
#include "node.h"
template<typename T> class LinkedList {
public:
LinkedList();
~LinkedList();
void add(T);
void print();
private:
Node<T> *head;
Node<T> *tail;
};
#endif//_LINKEDLIST_H
template<typename T>LinkedList<T>::LinkedList()
: head(0), tail(0)
{ /* empty */ }
template<typename T>LinkedList<T>::~LinkedList() {
if(head) {
Node<T> *p = head;
Node<T> *q = 0;
while(p) {
q = p;
p = p->next;
delete q;
}
cout << endl;
}
}
template<typename T>LinkedList<T>::void add(T info) {
if(head) {
tail->next = new Node<T>(info);
tail = tail->next;
} else {
head = tail = new Node<T>(info);
}
}
template<typename T>LinkedList<T>::void print() {
if(head) {
Node<T> *p = head;
while(p) {
cout << p->data << "-> ";
p = p->next;
}
cout << endl;
}
}
You Should add new node in this way
Node<T>* temp=new node<T>;
Hope you Solved :)
#include<iostream>
using namespace std;
template < class data > class node {
private :
data t;
node<data > *ptr;
public:
node() {
ptr = NULL;
}
data get_data() {
return t;
}
void set_data(data d) {
t = d;
}
void set_ptr(node<data > *p) {
ptr = p;
}
node * get_ptr() {
return ptr;
}
};
template <class data > node < data > * add_at_last(data d , node<data > *start) {
node< data > *temp , *p = start;
temp = new node<data>();
temp->set_data(d);
temp->set_ptr(NULL);
if(!start) {
start = temp;
return temp;
}
else {
while(p->get_ptr()) {
p = p->get_ptr();
}
p->set_ptr(temp);
}
}
template < class data > void display(node< data > *start) {
node< data > *temp;
temp = start;
while(temp != NULL) {
cout<<temp->get_data()<<" ";
temp = temp->get_ptr();
}
cout<<endl;
}
template <class data > node < data > * reverse_list(node<data > * start) {
node< data > *p = start , *q = NULL , *r = NULL;
while(p->get_ptr()) {
q = p;
p = p->get_ptr();
q->set_ptr(r);
r = q;
}
p->set_ptr(r);
return p;
}
int main() {
node < int > *start;
for(int i =0 ; i < 10 ; i ++) {
if(!i) {
start = add_at_last(i , start);
}
else {
add_at_last(i , start);
}
}
display(start);
start = reverse_list(start);
cout<<endl<<"reverse list is"<<endl<<endl;
display(start);
}