STL & Overloading in C++ - c++

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.)

Related

C++ N-ary tree, building a custom iterator with postfix operator taking in a parameter

I am trying to build a N-ary tree custom iterator. The nodes in the tree (MoveTreeNode*) have member values MoveTreeNode* m_parent to go to the previous node, and vector <MoveTreeNode*> m_children to go to the next nodes.
I want my iterator's postfix operator to take the parameter value int i which represents the index where the iterated node should descend in its m_children vector.
The key of the node is an object of type Move.
MoveTreeNode.hpp
#pragma once
#include "Move.hpp"
using namespace std;
class MoveTreeNode {
public:
MoveTreeNode(Move&);
Move& m_move; // Key
MoveTreeNode* m_parent; // To go to previous move
vector<MoveTreeNode*> m_children; // To to go to next move
};
MoveTree.hpp
#pragma once
#include "Move.hpp"
#include "MoveTreeNode.hpp"
using namespace std;
class MoveTree {
public:
MoveTreeNode* m_root = nullptr; // Root of the tree
// ( ... some member functions here)
struct Iterator {
using iterator_category = bidirectional_iterator_tag;
using difference_type = ptrdiff_t;
Iterator(MoveTreeNode* ptr): m_node(ptr) {};
MoveTreeNode& operator*() const { return *m_node; }
MoveTreeNode* operator->() { return m_node; }
// Prefix increment
// Iterator& operator++(int i) {
// m_node= m_node->m_children.at(i); return *this;
// }
// ^^^^^^error : cannot overload functions distinguished by return type alone
// Postfix increment
Iterator operator++(int i) {
Iterator tmp = m_node; m_node= m_node->m_children.at(i); return tmp;
}
// Prefix decrement
Iterator& operator--() { m_node = m_node->m_parent; return *this; }
// Postfix decrement
Iterator operator--(int) {
Iterator tmp = m_node; m_node = m_node->m_parent; return tmp;
}
friend bool operator== (const Iterator& a, const Iterator& b) { return a.m_node== b.m_node; };
friend bool operator!= (const Iterator& a, const Iterator& b) { return a.m_node!= b.m_node; };
private:
MoveTreeNode* m_node;
};
Iterator begin() { return Iterator(m_root); }
Iterator end() { return Iterator(nullptr); }
};
Issues encountered
Is it possible to have the increment operator overloaded such that it takes in a parameter, in this case an integer representing an index ?
I am not sure whether both prefix and postfix operators have to be specified? If I never use the prefix operator can I just define the postfix operator ? Because in the above snippet of code if I uncomment the prefix definition then I get the compilation error cannot overload functions distinguished by return type alone and I am not sure how to respond to that.
It's my first time trying to build a custom iterator, is my above struct correct, or is there something I am missing and should modify ?

How to enable conversion template argument T to const T?

Suppose that I have a following class
template <typename T>
struct Node { T value; Node* next; };
Often one needs to write code similar to this (let's assume that Sometype is std::string for now, although I don't think that it matters).
Node<SomeType> node = Node{ someValue, someNodePtr };
...
Node <const SomeType> constNode = node; // compile error
One way to work around is to define explicit conversion operator:
template <typename T>
struct Node
{
T value;
Node* next;
operator Node<const T>() const {
return Node<const T>{value, reinterpret_cast<Node<const T>* >(next)};
}
};
Is there a better, "proper" way to do it?
1. In general, what is the proper way to allow conversion of SomeType to SomeType except explicitly defining conversion operator? (Not in my example only).
2. If defining conversion operator is necessary, is reinterpret_cast is the proper way to do it? Or there are "cleaner" ways?
EDIT: Answers and comments were very helpful. I decided to provide more context right now. My problem is not with implementing const_iterator itself (I think that I know how to do it), but how to use same template for iterator and const_iterator. Here is what I mean
template <typename T>
struct iterator
{
iterator(Node<T>* _node) : node{ _node } {}
T& operator*() { return node->value; } // for iterator only
const T& operator*() const { return node->value; } // we need both for iterator
// for const iterator to be usable
iterator& operator++() { node = node->next; return *this; }
iterator operator++(int) { auto result = iterator{ node }; node = node->next; return result; }
bool operator==(const iterator& other) { return node == other.node; }
bool operator!=(const iterator& other) { return Node != other.node; }
private:
Node<T>* node;
};
Implementing const_iterator is essentially the same, except that T& operator*() { return node->value; }.
The initial solution is just to write two wrapper classes, one with T& operator*() and the other one without. Or use inheritance, with iterator deriving from const_iterator (which might be a good solution and has an advantage - we don't need to rewrite comparison operators for iterator and can compare iterator with const_iterator - which most often makes sense - as we check that they both point at same node).
However, I am curious how to write this without inheritance or typing same code twice. Basically, I think that some conditional template generation is needed - to have the method T& operator*() { return node->value; } generated only for iterator and not const_iterator. What is the proper way to do it? If const_iterator treated the Node* as Node*, it almost solves my problem.
Is there a better, "proper" way to do it?
There must be since your solution both has a weird behavior and is also invalid as specified by the C++ standard.
There's a rule called strict aliasing which dictate what kind of pointer type can alias another type. For example, both char* and std::byte* can alias any type, so this code is valid:
struct A {
// ... whatever
};
int main() {
A a{};
std::string b;
char* aptr = static_cast<void*>(&a); // roughtly equivalent to reinterpret
std::byte* bptr = reintepret_cast<std::byte*>(&b); // static cast to void works too
}
But, you cannot make any type alias another:
double a;
int* b = reinterpret_cast<int*>(&a); // NOT ALLOWED, undefined behavior
In the C++ type system, each instantiation of a template type are different, unrelated types. So in your example, Node<int> is a completely, unrelated, different type than Node<int const>.
I also said that your code has a very strange behavior?
Consider this code:
struct A {
int n;
A(int _n) : n(_n) { std::cout << "construct " << n << std::endl; }
A(A const&) { std::cout << "copy " << n << std::endl; }
~A() { std::cout << "destruct " << n << std::endl; }
};
Node<A> node1{A{1}};
Node<A> node2{A{2}};
Node<A> node3{A{3}};
node1.next = &node2;
node2.next = &node3;
Node<A const> node_const = node1;
This will output the following:
construct 1
construct 2
construct 3
copy 1
destruct 1
destruct 3
destruct 2
destruct 1
As you can see, you copy only one data, but not the rest of the nodes.
What can you do?
In the comments you mentionned that you wanted to implement a const iterator. That can be done without changing your data structures:
// inside list's scope
struct list_const_iterator {
auto operator*() -> T const& {
return node->value;
}
auto operator++() -> node_const_iterator& {
node = node->next;
return *this;
}
private:
Node const* node;
};
Since you contain a pointer to constant node, you cannot mutate the value inside of the node. The expression node->value yield a T const&.
Since the nodes are there only to implement List, I will assume they are abstracted away completely and never exposed to the users of the list.
If so, then you never have to convert a node, and operate on pointer to constant inside the implementation of the list and its iterators.
To reuse the same iterator, I would do something like this:
template<typename T>
struct iterator_base {
using reference = T&;
using node_pointer = Node<T>*;
};
template<typename T>
struct const_iterator_base {
using reference = T const&;
using node_pointer = Node<T> const*;
};
template<typename T, bool is_const>
using select_iterator_base = std::conditional_t<is_const, const_iterator_base<T>, iterator_base<T>>;
Then simply make your iterator type parameterized by the boolean:
template<bool is_const>
struct list_basic_iterator : select_iterator_base<is_const> {
auto operator*() -> typename select_iterator_base<is_const>::reference {
return node->value;
}
auto operator++() -> list_basic_iterator& {
node = node->next;
return *this;
}
private:
typename select_iterator_base<is_const>::node_ptr node;
};
using iterator = list_basic_iterator<false>;
using const_iterator = list_basic_iterator<true>;
Maybe you want another class altogether, like this:
template<typename T>
struct NodeView
{
T const& value; // Reference or not (if you can make a copy)
Node<T>* next;
NodeView(Node<T> const& node) :
value(node.value), next(node.next) {
}
};
Demo
If however you are talking about an iterator or a fancy pointer (as you mention in the comments), it's quite easy to do with an additional template parameter and some std::conditional:
template<typename T, bool C = false>
class Iterator {
public:
using Pointer = std::conditional_t<C, T const*, T*>;
using Reference = std::conditional_t<C, T const&, T&>;
Iterator(Pointer element) :
element(element) {
}
Iterator(Iterator<T, false> const& other) :
element(other.element) {
}
auto operator*() -> Reference {
return *element;
}
private:
Pointer element;
friend Iterator<T, !C>;
};
Demo

++ operator for a BST Class

I have already created a BST class, with a root node, and left and right node. It is working perfectly. I am trying to create a ++ operator Iterator, which can just go through each node and increment its. This is what I get so far, I am still thinking it gets something to do with my constructor. Below is just the nested Iterator class that I included in the BST class. I just cout to see if it is working but it keeps printing out 0.
class Iterator
{
private:
// private iterator state...
nodeptr root;
public:
Iterator(nodeptr roots_) : root(roots_) {};
~Iterator() {}
bool operator!=(const Iterator& rhs) const { return (this-> root != rhs.root); }
bool operator==(const Iterator& rhs) const {
return (this->root == rhs.root);
}
Iterator operator++(T) {
nodeptr ptr = root;
if (root == NULL)
{
cout << "The tree is empty" << endl;
}
else
{
if (ptr->left != NULL)
{
ptr = ptr->left;
}
cout << ptr->data << " ";
if (ptr->right != NULL)
{
ptr = ptr->right;
}
else
{
cout << "_";
}
}
return *this;
}
}
I don't know what a iterator should do in a BST class, anyway...
(1) I don't know what is a operator++ (T); as far I know, as method of a class, operator++ can be with signature operator++() (pre-increment) or operator++(int) (post-increment); I suppose you're trying to define a post-increment operator (because you add a dummy argument and because you returning a copy of Iterator, not a reference) but the dummy argument should be of type int, not of type T
(2) pre-increment or post-increment, the operator++() should modify the object; your operator doesn't modify it: it create a local copy of the lonely member (root) and modify the local copy; sequential calls to your operator++(T) should give the same effect because are doing the same thing; I suppose your intention was to modify the member root, instead of the local variable ptr
(3) supposing (presence of the dummy argument and no reference in return type) your intention was the make a post-increment operator, you have to create a copy of the object, modify the object and return the copy; you're (not) modifying the object and returning the object itself (return *this;) and this is the typical behavior (adding some change in object and return by reference) of a pre-increment operator.
To make it simple, I suppose you should write something as
// v <--- observe the return by reference
Iterator & operator++ ()
{
// something that modify the Iterator object
// return the object itself as reference
return *this;
}
// no reference here: return a copy
Iterator operator++ (int)
{
// copy of the object **before** the increment
// (but you have also to develop a copy constructor)
Iterator copy { *this };
// pre-increment of the object
++(*this);
// return of the before the increment copy
return copy;
}

Overloading operator compile error?

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.

No viable conversion from 'Template<int>::Memberclass' to 'const int'

I'm having a problem with return value/reference. I'm writing a template (queue), and Front() function is supposed to return the element from the front of the queue, but I get an error -- No viable conversion from 'Queue<int>::Node' to 'const int'. When I remove const, I get Non-const lvalue reference to type 'int' cannot bind to a value of unrelated type 'Queue<int>::Node' instead, and other variations of reference/no reference, const/no const give me either of the two errors. What am I missing?
#include <iostream>
using namespace std;
template <typename T>
class Queue
{
friend ostream& operator<< (ostream &, const Queue<T> & );
private:
class Node
{
friend class Queue<T>;
public:
Node(const T &t): node(t) {next = 0;}
private:
T front;
T back;
T node;
Node *next;
};
Node *front;
Node *back;
public:
Queue() : front(0), back(0) {}
~Queue();
bool Empty()
{
return front == 0;
}
T& Front()
{
if (Empty())
cout << "Очередь пуста." << endl;
else
{
T const & temp = *front; // error here
return temp;
}
}
/* ... */
};
template <class T> ostream& operator<< (ostream &, const Queue<T> & );
int main()
{
Queue<int> *queueInt = new Queue<int>;
for (int i = 0; i<10; i++)
{
queueInt->Push(i);
cout << "Pushed " << i << endl;
}
if (!queueInt->Empty())
{
queueInt->Pop();
cout << "Pop" << endl;
}
queueInt->Front();
return 0;
}
Your Node class definition doesn't make much sense: the way it's now, each node stores 3 data values: front, back and node. Is the class supposed to be a queue of triples?
Nevertheless, in your Front() function, you to need to return the "payload" of the front node (i.e. return something of type T), not the node itself. Something like this:
T& Front()
{
if (Empty())
cout << "Очередь пуста." << endl;
else
{
return front->node;
}
}
Replace
T const & temp = *front;
with
T& temp = front->front;
Queue<T>::front is a pointer to a Node, in other words, *front is a Node. You are trying then to assign a Node to a T& const and, since the compiler cannot convert from Node to T it complains. Now, the Node has a member also called front which is T and I suppose that's what you want to return and that's what the fix does. (Possibly you want to return front->node. Your intent is not clear to me.)
In addition, you declared temp as T const & and Front returns it. However, the type returned by Front is T& (non nonst) and the compiler cannot convert from const to non-const. By declaring temp non-const (as in the fix) such conversion is no longer required.