So I'm trying to overload the ^ operator to perform the intersection between my two sets, but I keep getting this compile time error "Invalid operands to binary expression.
intersection = list ^ listTwo; is what causes the error
My methods work fine without overloading.
Here is my header file.
#ifndef SetHeader_h
#define SetHeader_h
template<typename T>
class Node{
public:
T data;
Node<T> *next;
};
template<typename T>
class SetADT{
private:
Node<T> *head;
public:
SetADT();
~SetADT();
void add(T data);
void print();
bool isDuplicate(T data) const;
SetADT<T> operator ^ (SetADT<T> node);
};
#endif /* SetHeader_h */
Here is my cpp file
#include <iostream>
#include "SetHeader.h"
using namespace std;
template <typename T>
SetADT<T> ::SetADT(){
head = NULL;
}
template<typename T>
SetADT<T> :: ~SetADT<T>(){
cout<<"Set deleted!" << endl;
}
template<typename T>
bool SetADT<T>::isDuplicate(T data) const{
Node<T> *cur = this->head;
while (cur) {
if (cur->data == data) {
return true;
}
cur=cur->next;
}
return false;
}
template <typename T>
void SetADT<T>:: add(T data){
Node<T> *node = new Node<T>();
bool isPresent = isDuplicate(data);
if (!isPresent) {
node->data = data;
node->next = this->head;
this->head = node;
}
}
template <typename T>
void SetADT<T>:: print(){
Node<T> *head = this->head;
if (head == NULL) {
cout << "{}";
}
Node<T> *cur = head;
while (cur) {
cout << cur->data << ' ';
cur = cur->next;
}
cout << endl;
}
template <typename T>
SetADT<T> SetADT<T> :: operator &(SetADT<T> one){
SetADT<T> result;
Node<T> *setACurrent = this->head;
while (setACurrent) {
if (one.isDuplicate(setACurrent->data)) {
result.add(setACurrent->data);
}
setACurrent = setACurrent->next;
}
return result;
}
int main (){
SetADT<int> list;
list.add(10);
list.print();
SetADT<int> listTwo;
listTwo.add(10);
list.print();
SetADT<int> intersection;
//error right here
intersection = list ^ listTwo;
return 0;
}
The essence of your problem is that the operator function is defined for the class SetADT<T>, however you are are trying to invoke the ^ operator against pointers (to objects); the compiler does not match your operator function implementation to your usage. Only the bitwise-xor (^) operator is defined and it does not know how to handle SetADT<T> arguments.
In order for the complier to match the invocation with your declaration, you need to dereference the left-hand "argument," list.
intersection = *list ^ listTwo;
I might suggest that you write the operator to accept reference arguments rather than pointers, like so:
SetADT<T>* operator ^ (SetADT<T> &node) { … }
Then you invoke it,
intersection = *list ^ *listTwo;
Of course you can leave the existing declaration/definition in place if there is a reason for it, but it is not nice. You should consider returning a reference to the object rather than a pointer. And, for completeness, you should consider implementing the ^= operator, as well.
SetADT<T>& operator ^ (SetADT<T> &node);
SetADT<T>& operator ^=(const X& rhs);
Then the expression to use for ^ operator could look like,
*intersection = *list ^ *listTwo;
list ^ listTwo;
Both list and listTwo are a SetADT<int> *, a pointer to an instance of this template. Both operands of this ^ operator are pointers.
template<typename T>
class SetADT{
// ...
SetADT<T>* operator ^ (SetADT<T> *node);
Here you defined the ^ operator of a SetADT<T>, and not a SetADT<T> *.
This operator^ declaration ends up overloading an operator on an instance of the class, and not on a pointer to the instance of the class.
That's how operator members work: they overload an operator on an instance of the class, and not on a pointer to an instance of the class.
If you would like to invoke this operator correctly, the right syntax would be:
(*list) ^ listTwo
Here, *list dereferences a pointer to an instance of a class, so you end up with (a reference to) an instance of the class, which has an operator^ overload that takes a pointer to an instance of the same class as a parameter.
Note that your operator overload's parameter is a pointer to an instance of the class, and since listTwo is such a pointer, this should work.
The general mistake you are making is that you are not correctly understanding the fundamental difference between a class and a pointer to an instance of the class. The is not a trivial matter, it's an important distinction. If something is defined to work for an instance of a class, it expects to have an instance of a class to work with, and not a pointer of such a class. And vice-versa.
Related
I'm learning about linked list. I created a template implementation, with a constructor, an inserter, a destructor, a copy constructor and an overloaded assignment operator. The problem is that my test programme doesn't output anything after overloading assignment operator.
For my assignment operator, I use a Clear() function to clear the list entirely before the copy. I put it in the destructor and checked that it works fine. I also checked my copy constructor and it worked fine as well.
File node.h: defines the node building block
#include <iostream>
using namespace std;
template <typename T>
struct Node{
T _item;
Node<T>* _next;
Node() {
_item = T();
_next = NULL;
}
Node(T item){
_item = item;
_next = NULL;
}
// Print the value of a node
friend std::ostream& operator <<(std::ostream& outs, const Node<T> &printMe){
outs << "[" << printMe._item << "]";
return outs;
}
};
File list.h: defines the linked list template
#include "node.h"
template <class T>
class List {
public:
// default constructor
List();
// Destructor
~List();
// Copy constructor
List(const List<T> ©This);
// Overloading assignment operator
List& operator =(const List& RHS);
// Insert i to the head of the linked list
Node<T>* InsertHead(T i);
// Clear a linked list
void Clear();
// Overload the output operator to print the list
template <class U>
friend ostream& operator <<(ostream& outs, const List<U>& l);
private:
Node<T>* head;
};
This header also provides the implementation of these member functions:
template <class T>
List<T>::List(){
head = NULL;
}
template <class T>
List<T>::~List(){
Clear();
}
template <class T>
List<T>::List(const List<T> ©This){
if (copyThis.head == NULL)
head = NULL;
else {
// Create walker for the original linked list
Node<T>* walker = copyThis.head->_next;
// Create new head node for new linked list
head = new Node<T>(copyThis.head->_item);
// Create new walker for new linked list
Node<T>* new_walker = head;
// Iterate walker and new walker and copy each item in the original list to new linked list
while (walker!= NULL) {
new_walker->_next = new Node<T>(walker->_item);
walker = walker->_next;
new_walker = new_walker->_next;
}
}
}
template <class T>
List<T>& List<T>::operator =(const List<T>& RHS){ // DOESN'T WORK
if (this != &RHS) {
this->Clear();
*this = List<T>(RHS);
}
return *this;
}
template <class T>
Node<T>* List<T>::InsertHead(T i){
Node<T>* temp = new Node<T>(i);
temp->_next = head;
head = temp;
return head;
}
// Clear a linked list
template <class T>
void List<T>::Clear(){
Node<T>* current = head;
Node<T>* next = new Node<T>;
while (current != NULL) {
next = current->_next;
delete current;
current = next;
}
head = NULL;
}
template <class U>
ostream& operator <<(ostream& outs, const List<U>& l){
Node<U>* walker = l.head;
while(walker != NULL){
outs << *walker;
outs << "->";
walker = walker->_next;
}
outs << "|||";
return outs;
}
File main.cpp: tests the classes
#include <iostream>
#include "list.h"
using namespace std;
int main() {
List<int> a;
a.InsertHead(17);
a.InsertHead(35);
a.InsertHead(6);
a.InsertHead(54);
a.InsertHead(6);
cout << a <<endl;;
List<int> b;
b.InsertHead(3);
b.InsertHead(2);
cout << b <<endl;;
a = b;
cout << a <<endl; // PROBLEM: NOTHING IS DISPLAYED
cout << b <<endl;
}
The problem I currently have is the overloading assignment operator function. Below is when I copy the whole execution from the copy constructor function and it runs.
template <class T>
List<T>& List<T>::operator =(const List<T>& RHS){
if (this != &RHS) {
this->Clear();
if (copyThis.head == NULL)
head = NULL;
else {
// Create walker for the original linked list
Node<T>* walker = copyThis.head->_next;
// Create new head node for new linked list
head = new Node<T>(copyThis.head->_item);
// Create new walker for new linked list
Node<T>* new_walker = head;
// Iterate walker and new walker and copy each item in the original list to new linked list
while (walker!= NULL) {
new_walker->_next = new Node<T>(walker->_item);
walker = walker->_next;
new_walker = new_walker->_next;
}
}
return *this;
}
The output for this is:
2->3->|||
However, when I simplify the code like below, it doesn't output anything:
template <class T>
List<T>& List<T>::operator =(const List<T>& RHS){
if (this != &RHS) {
this->Clear();
*this = List<T>(RHS);
}
return *this;
}
Can anyone tell me why it doesn't work and how to simplify it efficiently? I really appreciate it.
The problem
The assignment operator stops everything because of a stack overflow.
In fact, your implementation of the assignment operator uses itself the assignment operator, so that it calls itself recursively until the stack is exhausted:
*this = List<T>(RHS); // OUCH !!
| | |
V V V
<ListT> operator= List<T> ==> cals operator= again !!
The solution
Rewrite the operator so that it doesn't call itself.
Possibly clone every node, so to avoid that 2 lists share the same node and tha the first one that frees its node causes dangling pointers and UB for the other.
Not related, but please avoid using namespaces in headers. This is an extremely bad habit for later.
Additional tip: This article recommends some good and elegant practices for operator overloading. For the assignment operator, it suggests to use the copy constructor (as you attempt to do) but instead of assigning (your problem), swapping (to be verified, but swapping the heads in your case would certainly do the trick).
I am attempting to code an assignment operator for a linked list class in c++. The errors I'm getting say that "head" is undeclared, but I'm not sure where I'm supposed to declare it. It's being used in other functions without a problem. Another error says my use of "this" is invalid.
template <class T>
SortedLinkList<T>& operator=(const SortedLinkList<T> & otherList)
{
if(&otherList != this) {
Node<T> temp = head;
while(temp->getNext() != NULL) {
head = head -> getNext();
delete temp;
temp = head;
}
count = 0;
temp = otherList.head;
while(temp != NULL) {
insert(temp);
}
}
return *this;
}
The this pointer is unavailable because your function signature does not resemble a member definition, you're missing the type scope resolution part of the signature:
template <class T>
SortedLinkList<T>& operator=(const SortedLinkList<T> & otherList)
should be:
template <class T>
SortedLinkList<T>& SortedLinkList<T>::operator=(const SortedLinkList<T> & otherList)
I am creating a class LinkedList. I am having difficulty adding another node to my list.
Here is what I have so far:
template<typename T>
class LinkedList
{
private:
T element;
T *next;
public:
LinkedList();
LinkedList(T element);
void add(LinkedList<T> &otherList);
void print();
};
template<typename T>
LinkedList<T>::LinkedList()
{
next = NULL;
}
template<typename T>
LinkedList<T>::LinkedList(T element)
{
this->element = element;
next = NULL;
}
template<typename T>
void LinkedList<T>::add(LinkedList<T> &otherList)
{
next = &otherList;
}
template<typename T>
void LinkedList<T>::print()
{
LinkedList<T> *current = this;
while (current != NULL)
{
std::cout << current->element;
current = current->next;
}
}
int main()
{
LinkedList<std::string> myFirst("First");
LinkedList<std::string> mySecond("Second");
myFirst.add(mySecond);
myFirst.print();
return 0;
}
This works however if I make the change:
void add(const LinkedList<T> &otherList);
template<typename T>
void LinkedList<T>::add(const LinkedList<T> &otherList)
{
next = &otherList; //now an error right here
}
Then I get an error stating:
Assigning to 'LinkedList<std::__1::basic_string<char> > *' from incompatible type 'const LinkedList<std::__1::basic_string<char> > *'
Why is it I get this error?
next is a T*, and you're trying to assign a const LinkedList<T>* to it.
I suppose you meant something like next = &(otherList.element) (though even then I think your list semantics are somewhat broken — elements shouldn't typically be shared by multiple containers unless you're very, very clear about the ownership semantics).
Contrary to your claims, your first program doesn't work either for the same reason.
I've created a doubly-linked list out of nodes. I'm working with the STL. I'm getting an error in the operator++ function. Here's my Iterator<T> class.
#include "Node.h"
#include <iostream>
using namespace std;
template<class T> class Iterator{
public:
Iterator();
~Iterator();
Node<T> *node;
void operator++(Iterator<T> val);
void operator--();
T operator*();
private:
};
template<class T>
Iterator<T>::Iterator(){
node = 0;
}
template<class T>
Iterator<T>::~Iterator(){
}
template<class T>
void Iterator<T>::operator++(Iterator<T> val){
if(node != 0){
node = node->next;
}
}
template<class T>
void Iterator<T>::operator--(){
if(node != 0)
node = node->prev;
}
template<class T>
T Iterator<T>::operator*(){
if(node == 0){
cout << "Node no exists!";
}
else{
return node->value;
}
}
I'm also getting a warning in my main function.
#include <iostream>
#include "List.h"
using namespace std;
int main()
{
List<int> mylist;
for(int i = 2; i < 10; i++){
mylist.push_back(i);
}
Iterator<int> it = mylist.begin();
while(it.node->next != 0){
cout << it.node->value << "\n";
it++;
}
mylist.pop_front();
cout << mylist.front() << ", ";
cout << mylist.back();
return 0;
}
ERRORS AND WARNINGS
F:\New folder\C++\Lab14\Iterator.h||In instantiation of 'class
Iterator':|
F:\New folder\C++\Lab14\main.cpp|15|required from here|
F:\New folder\C++\Lab14\Iterator.h|29|error: postfix 'void
Iterator::operator++ (Iterator) [with T = int]' must take 'int'
as its argument|
F:\New folder\C++\Lab14\main.cpp||In function 'int main()':|
F:\New folder\C++\Lab14\main.cpp|19|error: no 'operator++(int)'
declared for postfix '++' [-fpermissive]|
By the way, I'm planing to do the same with the other operators too. The operator* is not for multiplication.
operator++ must either take a single int or no argument:
void operator++(int);
void operator++();
The first is the overload for postfix ++ and the second for prefix ++. The int argument is only to allow the correct overload to occur; its value is unspecified.
Your declaration of operator++ currently looks like this:
void operator++(Iterator<T> val);
It seems like you're expecting the object that is being incremented to be passed as an argument. Actually, the object is the object pointed to by this. You would implement your operator++ like so:
template<class T>
Iterator<T> Iterator<T>::operator++(int) {
Iterator<T> copy = *this;
if(node != 0) {
node = node->next;
}
return copy;
}
Note that I've also returned a copy of the object before changing its node member. This is usually expected of a postfix increment operator.
To get prefix increment, overload with no argument. It should return *this by reference. ie.
Iterator operator++(int); // postfix
Iterator & operator++(); // prefix
Like most operators, there are two ways you can define operator++. You can write it as a member of the iterator class, or as a free function. But there's another complication, because there are two forms of operator++: prefix and postfix. So writing that operator takes a bit more thought.
As a member:
struct Iterator {
Iterator& operator++(); // prefix
Iterator operator++(int); // postfix
};
As a free function:
struct Iterator { };
Iterator& operator++(Iterator&); // prefix
Iterator operator++(Iterator&, int); // postfix
operator++ shouldn't take an argument. Removing the argument from both the prototype and definition should fix your error.
And just as a little 'pointer' (get it?), the dereference operator probably should return a node<T>, not T. (You can do both, but the former makes more sense, and would make it behave in a similar way to std containers.)
I have the following main.cpp file
#include "listtemplate.h"
//#include <iostream>
using namespace std;
int main()
{
int UserChoice;
cout << "Hello, World!" << endl;
cin >> UserChoice;
cout << UserChoice;
}
In it's current form, everything works. I enter an integer, and that integer is printed to the screen. However, when I uncomment the cout << "Hello, World!" << endl line, I get the following error
main.cpp:10: error: ambiguous overload for ‘operator<<’ in ‘std::cout << "Hello, World!"’
I can also make it work by commenting out #include "listtemplate.h", uncommenting the hello world line, and including <iostream> in main (currently accessible through the template. Can anyone see what I'm missing here?
listtemplate.h
#ifndef LISTTEMPLATE_H
#define LISTTEMPLATE_H
#include "list.h"
using namespace std;
// Default constructor
template <class Type>
list<Type> :: list() : Head(NULL) {}
// Destructor
template <class Type>
list<Type> :: ~list()
{
Node *Temp;
while (Head != NULL)
{
Temp = Head;
Head = Head -> Next;
delete Temp;
}
}
// Copy constructor
template <class Type>
list<Type> :: list (const Type& OriginalList)
{
Node *Marker;
Node *OriginalMarker;
OriginalMarker = OriginalList.Gead;
if (OriginalMarker == NULL) Head = NULL;
else
{
Head = new Node (OriginalMarker -> Element, NULL);
Marker = Head;
OriginalMarker = OriginalMarker -> Next;
while (OriginalMarker != NULL)
{
Marker -> Next = new Node (OriginalMarker -> Next);
OriginalMarker = OriginalMarker -> Next;
Marker = Marker -> Next;
}
}
}
// Copy assignment operator
template <class Type>
list<Type>& list<Type> :: operator= (const list<Type>& Original)
{
Node *Marker;
Node *OriginalMarker;
// Check that we are not assigning a variable to itself
if (this != &Original)
{
// First clear the current list, if any
while (Head != NULL)
{
Marker = Head;
Head = Head -> Next;
delete Marker;
}
// Now build a new copy
OriginalMarker = Original.Head;
if (OriginalMarker == NULL) Head = NULL;
else
{
Head = new Node (OriginalMarker -> Element, NULL);
Marker = Head;
OriginalMarker = OriginalMarker -> Next;
while (OriginalMarker != NULL)
{
Marker -> Next = new Node (OriginalMarker -> Element, NULL);
OriginalMarker = OriginalMarker -> Next;
Marker = Marker -> Next;
}
}
}
return (*this);
}
// Test for emptiness
template <class Type>
bool list<Type> :: Empty() const
{
return (Head == NULL) ? true : false;
}
// Insert new element at beginning
template <class Type>
bool list<Type> :: Insert (const Type& NewElement)
{
Node *NewNode;
NewNode = new Node;
NewNode -> Element = NewElement;
NewNode -> Next = Head;
return true;
}
// Delete an element
template <class Type>
bool list<Type> :: Delete (const Type& DelElement)
{
Node *Temp;
Node *Previous;
// If list is empty
if (Empty()) return false;
// If element to delete is the first one
else if (Head -> Element == DelElement)
{
Temp = Head;
Head = Head -> Next;
delete Temp;
return true;
}
// If the list has only one element which isn't the specified element
else if (Head -> Next == NULL) return false;
// Else, search the list element by element to find the specified element
else
{
Previous = Head;
Temp = Head -> Next;
while ((Temp -> Element != DelElement) && (Temp -> NExt != NULL))
{
Previous = Temp;
Temp = Temp -> Next;
}
if (Temp -> Element == DelElement)
{
Previous -> Next = Temp -> Next;
delete Temp;
return true;
}
else return false;
}
}
// Print the contents of the list
template <class Type>
void list<Type> :: Print (ostream& OutStream) const
{
Node *Temp;
Temp = Head;
while (Temp != NULL)
{
OutStream << Temp -> Element << " ";
Temp = Temp -> Next;
}
}
// Overloaded output operator
template <class Type>
ostream& operator<< (ostream& OutStream, const list<Type>& OutList)
{
OutList.Print (OutStream);
return OutStream;
}
#endif
list.h
#ifndef LIST_H
#define LIST_H
#include <iostream>
#include <cstddef>
using namespace std;
template <class Type>
class list
{
private:
struct Node
{
public:
Type Element;
Node *Next;
Node() : Next(NULL) {} // Default constructor
Node (Type Data, Node *PNode = NULL) : // Non-default constructor
Element (Data),
Next (PNode) {}
};
Node *Head;
public:
list();
~list();
list (const Type& OriginalList);
bool Empty() const;
bool Insert (const Type& NewElement);
bool Delete (const Type& DelElement);
void Print (ostream& OutStream) const;
list& operator= (const list<Type>& Original);
};
template <class Type>
ostream& operator<< (ostream& OutStream, const Type& OutList);
#endif
This is in fact an interesting question. The main issue is, as others have pointed before that you have declared the following signature:
template <typename T>
std::ostream& operator<<( std::ostream&, T const & );
And that triggers the ambiguity, as it is a catch-all template. But why is it that the compiler can insert (unambiguously) an integer into cout but it cannot insert a const char*?
The reason for that is in the definition of the std::basic_ostream template and free functions that are required in the standard. In particular, the template class basic_ostream contains member functions to insert basic types, including int. On the other hand, the insertion of const char* into streams is defined as a templated free function. Bringing the three declarations together:
namespace std {
template <typename CharT, typename traits = char_traits<CharT> >
class basic_ostream {
// ...
basic_ostream<CharT,traits>& operator<<(int n); // [1]
// ...
};
template<class charT, class traits> // [2]
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const char*);
}
template <typename T> // [3]
std::ostream& operator<<( std::ostream&, T const & ); // user defined
Now, when the compiler encounters the expression std::cout << 5, it finds that [1] is a non-templated perfect match. It is non-templated as std::cout is an object of a concrete instantiation of the basic_ostream class template, when the compiler considers the members of that class, the type is fixed. The method itself is not templated.
The template [3] could match the same use, but because [1] is not templated it takes precedence in the overload resolution, and there is no ambiguity.
Now, when the compiler sees the expression std::cout << "Hello world";, it performs the lookup and it finds (among other options that cannot be matched and are thus discarded) options [2] and [3]. The problem is that now, both options are templates, the first one can be resolved by matching CharT = char and traits = char_traits<char>, while the second can be matched by making T = const char* (the first argument is a concrete instantiated type). The compiler cannot make up its mind (there is no partial order that defines which option it should follow), and it triggers the ambiguity error.
The really interesting point in the question is that while both [1] and [2] seem to be templated on the arguments CharT and traits basically in the same way they are not considered in the same way by the compiler, the reason for that is that lookup finds [1] as a member of std::cout, that means that in [1], basic_ostream<char,char_traits<char> > is the concrete known type of the first argument and it is fixed. The template is the class, not the function, and the class instantiation types are fixed before lookup considers the member functions. On the other hand, when it ADL finds [2] and tries to match against the call, basic_ostream<CharT, traits> is a generic type that can be matched to the type of cout.
I hope this is not too confusing, but I think it is nice to know the subtle difference of similarly looking code.
I think that the problem is that in your header you've prototyped this function:
template <class Type>
ostream& operator<< (ostream& OutStream, const Type& OutList);
instead of this one:
template <class Type>
ostream& operator<< (ostream& OutStream, const list<Type>& OutList);
The version you've prototyped says that it's an operator << that can print out anything, not lists of anything. Consequently, when you write
cout << "Hello, world!" << endl;
The compiler can't tell which function it's supposed to call - the standard output function or the one you've defined in your list header.
declared as:
ostream& operator<< (ostream& OutStream, const Type& OutList);
in the function definition as:
ostream& operator<< (ostream& OutStream, const list<Type>& OutList)