Custom Iterator to pretend element is in vector - c++

A class of element used to be stored in a vector with other similar elements.
But now, it been removed and moved into its own field in the parent object.
class OldParent {
vector<char> OldCollection = { 'A', 'B', 'C' };
}
class NewParent {
char A = 'A';
vector<char> NewCollection = { 'B', 'C' };
}
The type that is held by the vector is significantly more complicated than a character, it is a vector of a normalish struct.
So the actual original type would look something like this:
struct ActualType {
string val1;
int val2;
double val3;
}
vector<vector<ActualType>> OldCollection;
// vector that has been separated out
vector<ActualType> SeparatedCollection;
The problem is that alot of the original code uses iterators over the whole old collection and a clean way I thought I could implement this change would be to create an iterator that would work as if the separated field was never separated. This way much of the original code would not have to be changed.
However, I am definitely open to new ideas as well.
The use case looks like this:
The change means that one of the numbers will be permanently stored outside of the vector.
vector<int> nNums = {1,2,3};
void UseCase(int x)
{
int toRemove = 0;
for (auto& num : nNums)
{
if (num - x < 0)
{
toRemove++;
x -= num;
}
else
{
num -= x;
break;
}
for (int i = 0; i < toRemove; ++i)
nNums.erase(nNums.begin());
}
}

Here's a demo for a custom container that will take pointers to both the separated object and the container for the rest of the objects:
#include <vector>
#include <iostream>
#include <cmath>
template <typename T>
class CustomIterator;
template <typename T>
class CustomContainer
{
public:
CustomContainer(std::vector<T> *container, T *separated) : mContainer{container},
mSeparated{separated} {}
std::vector<T> *GetContainer() { return mContainer; }
T *GetSeparated() { return mSeparated; }
inline CustomIterator<T> begin() { return CustomIterator<T>(this); }
inline CustomIterator<T> end() { return CustomIterator<T>(this, mContainer->size() + 1); }
private:
std::vector<T> *mContainer;
T *mSeparated;
};
template <typename T>
class CustomIterator
{
public:
CustomIterator(CustomContainer<T> *container) : mCustomContainer{container}, mPos{0} {}
CustomIterator(CustomContainer<T> *container, int pos) : mCustomContainer{container}, mPos(pos) {}
CustomIterator(const CustomIterator<T> &other) = default;
const CustomContainer<T> *GetContainer() const { return mCustomContainer; }
const int GetPos() const { return mPos; }
~CustomIterator() {}
CustomIterator<T> &operator=(const CustomIterator<T> other)
{
mCustomContainer = other.GetContainer();
mPos = other.GetPos();
};
bool operator==(const CustomIterator<T> &other) { return other.GetContainer() == mCustomContainer && other.mPos == mPos; }
bool operator!=(const CustomIterator<T> &other) { return other.GetContainer() != mCustomContainer || other.mPos != mPos; }
CustomIterator<T> operator+=(const int &movement)
{
if (mPos + movement > mCustomContainer->GetContainer()->size() + 1)
mPos = mCustomContainer->GetContainer()->size() + 1;
else
mPos += movement;
return CustomIterator<T>(*this);
}
CustomIterator<T> operator-=(const int &movement)
{
if (mPos - movement < 0)
mPos = 0;
else
mPos -= movement;
return CustomIterator<T>(*this);
}
CustomIterator<T> operator++()
{
const auto maxSize = mCustomContainer->GetContainer()->size() + 1;
mPos = mPos == maxSize ? maxSize : mPos + 1;
return CustomIterator<T>(*this);
}
CustomIterator<T> operator--()
{
mPos = mPos == 0 ? 0 : mPos - 1;
return CustomIterator<T>(*this);
}
int operator-(const CustomIterator<T> &other) { return std::abs(other.GetPos() - mPos); }
T &operator*()
{
const auto maxSize = mCustomContainer->GetContainer()->size() + 1;
if (mPos == maxSize)
{
throw "Error: index out of bounds";
}
else if (mPos == 0)
{
return *(mCustomContainer->GetSeparated());
}
return (*mCustomContainer->GetContainer()).at(mPos - 1);
}
T &operator->() { this->operator*(); }
private:
CustomContainer<T> *mCustomContainer;
int mPos;
};
int main()
{
std::vector<int> container = {5, 6};
int separated = 4;
auto customContainer = CustomContainer<int>(&container, &separated);
for (auto i : customContainer)
{
std::cout << (i) << std::endl;
}
return 0;
}

Related

Sorting a ring buffer class objects

I am trying to make a sorting function for a ring buffer class object, but it gives me the below error and I couldn't remove it:
template placeholder type 'ring' must be followed by a simple declarator-id
argument list for class template "ring" is missing
'arr' was not declared in this scope
(arr) was declared in the parameter of the function but yet it does not recognize it
hopefully someone can explain what is wrong with the sorting function, here is below my code:
#include<iostream>
#include<initializer_list>
template<typename T>
void swap(T& x, T& y) {
T temp;
temp = x;
x = y;
y = temp;
}
template<typename T>
class ring {
public:
class iterator;
public:
ring(std::initializer_list<T>elements) {
sze = elements.size();
value = new T[sze];
for (auto& i : elements) {
add(i);
}
}
T& get(int x) { return value[x]; }
std::size_t size() { return sze; }
void add(T v) {
value[index++] = v;
if (index == sze)
index = 0;
}
iterator begin() { return iterator(0, *this); }
iterator end() { return iterator(sze, *this); }
friend void BubbleSort(ring& arr, std::size_t n);
~ring() { delete[] value; }
private:
int index = 0;
std::size_t sze;
T* value;
};
template<typename T>
class ring<T>::iterator {
public:
iterator(int x, ring& y) :index(x), obj(y) {}
iterator& operator++() { index++; return *this; }
iterator& operator++(int x) { index++; return *this; }
bool operator!=(const iterator& other) { return index != other.index; }
T& operator*() { return obj.get(index); }
private:
int index;
ring& obj;
};
template<typename T>
void BubbleSort(ring& arr, std::size_t n) { // here is the function of the sorting.
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr.value[j] > arr.value[j + 1]) {
swap(arr.value[j], arr.value[j + 1]);
}
}
}
}
Your friendly compiler showed you already the problem and in which line it happened.
And it gave you 3 error messages telling you exactly what the problem is.
See my compiler output
Your class ring needs a template parameter. So same as in line 49 of the picture.
The below will compile.
#include<iostream>
#include<initializer_list>
template<typename T>
void swap(T& x, T& y) {
T temp;
temp = x;
x = y;
y = temp;
}
template<typename T>
class ring {
public:
class iterator;
public:
ring(std::initializer_list<T>elements) {
sze = elements.size();
value = new T[sze];
for (auto& i : elements) {
add(i);
}
}
T& get(int x) { return value[x]; }
std::size_t size() { return sze; }
void add(T v) {
value[index++] = v;
if (index == sze)
index = 0;
}
iterator begin() { return iterator(0, *this); }
iterator end() { return iterator(sze, *this); }
friend void BubbleSort(ring& arr, std::size_t n);
~ring() { delete[] value; }
private:
int index = 0;
std::size_t sze;
T* value;
};
template<typename T>
class ring<T>::iterator {
public:
iterator(int x, ring& y) :index(x), obj(y) {}
iterator& operator++() { index++; return *this; }
iterator& operator++(int x) { index++; return *this; }
bool operator!=(const iterator& other) { return index != other.index; }
T& operator*() { return obj.get(index); }
private:
int index;
ring& obj;
};
template<typename T>
void BubbleSort(ring<T>& arr, std::size_t n) { // here is the function of the sorting.
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr.value[j] > arr.value[j + 1]) {
swap(arr.value[j], arr.value[j + 1]);
}
}
}
}
I did not check the functionality. Sorting a ringbuffer sounds somehow strange . . .

Using the function "find", of a set of struct, by passing just one attribute of the struct?

Is it possible to use the function "find", of a set of struct, by passing just one attribute of the struct?
The structs and the operators < are defined below:
struct ARCO_TEMPO {
Arco a;
int slotTimeU; // momento que sai do vertice u do arco
int slotTimeV; // momento que chega no vertice v do arco
int order;
ARCO_TEMPO () {};
ARCO_TEMPO (const ARCO_TEMPO& obj): a(obj.a), slotTimeU(obj.slotTimeU), slotTimeV(obj.slotTimeV), order(obj.order) {};
ARCO_TEMPO (Arco _a, int _slotTimeU, int _slotTimeV, int _order) : a(_a), slotTimeU(_slotTimeU), slotTimeV(_slotTimeV), order(_order) {}
};
struct PATH {
set<ARCO_TEMPO> rota;
float COST;
};
bool operator<(const ARCO_TEMPO& obj1, const ARCO_TEMPO& obj2) {
if (obj1.slotTimeU < obj2.slotTimeU) {
return true;
}
else {
if (obj1.slotTimeU == obj2.slotTimeU && obj1.slotTimeV < obj2.slotTimeV) {
return true;
}
else {
if (obj1.slotTimeU == obj2.slotTimeU && obj1.slotTimeV == obj2.slotTimeV && obj1.a.i < obj2.a.i) {
return true;
}
else {
if (obj1.slotTimeU == obj2.slotTimeU && obj1.slotTimeV == obj2.slotTimeV &&obj1.a.i == obj2.a.i && obj1.a.j < obj2.a.j ) {
return true;
}
else{
return false;
}
}
}
bool operator<(const PATH& obj1, const PATH& obj2) {
if (obj1.COST < obj2.COST) {
return true;
}
else {
if (obj1.COST == obj2.COST && obj1.rota < obj2.rota) {
return true;
}
else{
return false;
}
}
}
I have a variable PATH, called as aux_p. Then I have the attribute rota of this PATH (aux_p.rota). I want to find the "position" in the set rota (aux_p.rota), in which the attribute order is equal a specific value.
I tried the lines below, but it doesn't work:
set<ARCO_TEMPO>::iterator it;
int orderAux = aux_p.rota.size();
it = aux_p.find(it->orderAux)
How can I use a second container unordered_map to this works?
Could anyone help me, please?
What you want is impossible. Either iterate through all set elements from begin() to end(), or use a second container unordered_map<int>.
BTW ARCO_TEMPO::orderAux and PATH::find are not declared.

Cref postincrementation in Map definition

So I have such definition on map class on vector, it works good except for post-incrementation, which doesn't work as it should. You can see in example that variable a should be equal to 10 (post-incremented after assignment). But it's equal to 11. I have no idea how to fix that.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
template<class T>
class Map {
class Cref {
friend class Map;
Map& m;
string key;
T value;
public:
operator double() {
return m.read(key);
};
Map::Cref & operator=(double num) {
m.write(key, num);
return *this;
};
Map::Cref & operator++(int) {
Cref c(*this);
m.increment(key, value);
return c;
}
Cref(Map& m, string a)
: m(m),
key(a) {};
};
public:
class Unitialized {};
struct Record {
string key;
T value;
};
vector<Record> data;
Map() {}
~Map() {}
bool ifexist(string k) {
for (int i = 0; i < data.size(); i++) {
if (data.at(i).key == k)
return 1;
}
return 0;
}
Cref operator[](string key) {
return Map::Cref( * this, key);
}
private:
void increment(string key, T value) {
if (ifexist(key) == 0) {
throw Unitialized();
}
for (int i = 0; i < data.size(); i++) {
if (data.at(i).key == key)
data.at(i).value += 1;
}
}
void write(string key, T value) {
if (ifexist(key) == 1) {
cout << "Element already exist" << endl;
return;
}
Record r;
r.key = key;
r.value = value;
data.push_back(r);
}
double read(string key) {
if (ifexist(key) == 0) {
throw Unitialized();
}
for (int i = 0; i < data.size(); i++) {
if (data.at(i).key == key)
return data.at(i).value;
}
return 0;
}
};
int main(int argc, char** argv) {
Map<int> m;
m["ala"] = 10;
int a = 0;
a = m["ala"]++;
cout << a << endl;
try {
cout << m["ala"] << endl;
cout << m["ola"] << endl;
} catch (Map<int>::Unitialized&) {
cout << "Unitialized element" << endl;
}
return 0;
}
Yes, I already fixed that, overloading of ++ operator should look like that :
T operator ++(int)
{
T ret = m.read(this->key);
m.increment(key, value);
return ret;
}
This fixes everything.

C++ Undefined reference to List<int>::GetCount() const [duplicate]

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 9 years ago.
I am writing a simple data structure library, while I met some problems.
I wrote three files. collections.h is the header file, collections.cpp is to implement the methods declared in header file, main.cpp is for test. But compile error occurs:
Undefined reference to List::GetCount() const;
Undefined reference to List::IsEmpty() const;
Undefined reference to List::Add(int);
...// And so on.
I provide my code below, where is the problem?
collections.h:
#ifndef COLLECTIONS_H
#define COLLECTIONS_H
#include <windows.h>
#include <stdexcept>
template<typename T>
class ISequenceList
{
protected:
ISequenceList() { }
public:
virtual int GetCount() const = 0;
virtual bool IsEmpty() const = 0;
virtual void Add(T item) = 0;
virtual void AddRange(const T *items, int length) = 0;
virtual T &ElementAt(int index);
virtual bool InsertAt(T item, int index);
virtual bool Remove(T item) = 0;
virtual bool RemoveAt(int index) = 0;
virtual bool Contains(T item) = 0;
};
template<typename T>
class List : public ISequenceList<T>
{
private:
int _count;
int _capacity;
T *_array;
void ExpandCapacity();
public:
List(int capacity = 100)
{
if (capacity <= 0)
std::__throw_invalid_argument("The capcity can't be 0 or below.");
this->_count = 0;
this->_capacity = capacity;
this->_array = (T*)malloc(_capacity* sizeof(T));
}
List(const List &other)
{
if (this == other)
return;
this->_count = other->_count;
this->_capacity = other->_capacity;
free(_array);
this->_array = other->_array;
}
List &operator=(const List &other)
{
this = other;
}
~List()
{
if (_array)
free(_array);
}
int GetCount() const;
bool IsEmpty() const;
T &ElementAt(int index);
void Add(T item);
void AddRange(const T *items, int length);
bool InsertAt(T item, int index);
bool Remove(T item);
bool RemoveAt(int index);
bool Contains(T item);
};
#endif
collections.cpp:
#include "collections.h"
template<typename T>
void List<T>::ExpandCapacity()
{
T *temp = this->_array;
this->_array = (T*)malloc((this->_capacity << 1) * sizeof(T));
memcpy(this->_array, temp, this->_capacity * sizeof(T));
this->_capacity = this->_capacity << 1;
free(temp);
}
template<typename T>
int List<T>::GetCount() const
{
return this->_count;
}
template<typename T>
bool List<T>::IsEmpty() const
{
return this->_count == 0;
}
template<typename T>
void List<T>::Add(T item)
{
this->_array[_count] = item;
_count++;
if (_count == _capacity)
this->ExpandCapacity();
}
template<typename T>
void List<T>::AddRange(const T *items, int length)
{
if (length <= 0)
std::__throw_invalid_argument("The length can't be 0 or below.");
if (!items)
std::__throw_invalid_argument("The items can't be null");
int totalLength = this->_count + length;
if (totalLength >= this->_capacity)
{
T *temp = this->_array;
this->_array = (T*)malloc((totalLength << 1) * sizeof(T));
memcpy(_array, temp, this->_capacity);
free(temp);
}
this->_array += this->_capacity;
memcpy(_array, items, length * sizeof(T));
this->_capacity = totalLength << 1;
this->_count += length;
}
template<typename T>
T &List<T>::ElementAt(int index)
{
if (index < 0 || index >= _count )
std::__throw_invalid_argument("The index is out of bound.");
return _array[index];
}
template<typename T>
bool List<T>::InsertAt(T item, int index)
{
if (index < 0 || index > _count)
return false;
if (index == _count)
{
this->Add(item);
return true;
}
for (int i = _count; i > index; i--)
{
_array[i] = _array[i - 1];
}
_array[index] = item;
_count++;
if (_count == _capacity)
this->ExpandCapacity();
return true;
}
template<typename T>
bool List<T>::Remove(T item)
{
for (int i = 0; i < _count; i++)
{
if (_array[i] == item)
{
for (int j = i; j < _count; j++)
{
_array[j] = _array[j + 1];
}
_count--;
return true;
}
}
return false;
}
template<typename T>
bool List<T>::RemoveAt(int index)
{
if (index < 0 || index >= _count)
return false;
for (int j = index; j < _count; j++)
{
_array[j] = _array[j + 1];
}
_count--;
return true;
}
template<typename T>
bool List<T>::Contains(T item)
{
for (int i = 0; i < _count; i++)
{
if (_array[i] == item)
return true;
}
return false;
}
main.cpp:
#include "collections.h"
#include <iostream>
int main()
{
List<int> *seqList = new List<int>();
seqList->Add(5);
int arr[100] = {0};
seqList->AddRange(arr, 50);
seqList->ElementAt(5) = 111;
seqList->InsertAt(100, 15);
seqList->Remove(50);
seqList->ElementAt(44) = 44;
seqList->RemoveAt(44);
if (seqList->Contains(111))
std::cout << "Yes" << std::endl;
for (int i = 0; i < seqList->GetCount(); i++)
{
std::cout << seqList->ElementAt(i) << "\t";
}
return 0;
}
I have defined all the methods in List, but why can't the complier recognize? Where is the problem? Thanks for anyone who help me..
Note: my ide is Code::Blocks
Implementation of the template functions must be in a header; it can't be in a separate source file. The compiler needs to see it at the point where the template is used and its arguments become known.

return value for overloaded operator

I'm sorry if this is a very basic question, I'm pretty new to C++.
I'm trying to define my own vector class and an iterator for it. However, whenever I overload an operator the value that is returned is always an address.
For instance, the following code prints 0x7fb6dbc000e0 0x7fb6dbc000e0 when I want it to print 1 0
Since I've been messing around with the syntax for a while, some of the operators look a little different, this is just so that you can see a few things I've tried.
test.cc
#include <iostream>
#include "TwoWayVector.cc"
int main(){
TwoWayVector<int> numbers;
numbers.push_back(3);
numbers.push_back(2);
TwoWayVectorIterator<int>* beginning = numbers.begin();
TwoWayVectorIterator<int>* beginning2 = numbers.begin();
cout << beginning==beginning2;
cout << beginning != beginning2;
cout << endl;
return 0;
}
TwoWayVector.cc
using namespace std;
#include "TwoWayVectorIterator.cc"
template <class T> class TwoWayVector{
public:
T* data;
int capacity;
int nextFree;
TwoWayVector(){
capacity = 10;
nextFree = 0;
data = new T[capacity];
}
~TwoWayVector(){
delete data;
}
T& operator[](const int index){
if( index >= capacity || capacity + index < 0){
string number = static_cast<ostringstream*>( &(ostringstream() << index) )->str();
string error = "index " + number + " is out of bounds";
throw error;
}
else if(index < 0){
return data[nextFree+index];
}
return data[index];
}
bool operator==(const TwoWayVector* vector2){
if(capacity != vector2->capacity){
return false;
}
if(nextFree != vector2->nextFree){
return false;
}
for(int i=0; i<nextFree ; i++){
if(data[i] != vector2[i]){
return false;
}
}
return true;
}
//memory leaks?
void push_back(T object){
if(capacity <= nextFree){
capacity = capacity*2;
T* tmp = new T[capacity];
for(int i=0; i<capacity; i++){
tmp[i] = data[i];
}
delete data;
data = tmp;
}
data[nextFree] = object;
nextFree++;
}
T pop_back(){
nextFree--;
T result = data[nextFree];
data[nextFree] = NULL;
return result;
}
int size(){
return nextFree;
}
TwoWayVectorIterator<T>* begin(){
TwoWayVectorIterator<T>* i = new TwoWayVectorIterator<T>(0,this);
return (i);
}
TwoWayVectorIterator<T>* end(){
TwoWayVectorIterator<T>* i = new TwoWayVectorIterator<T>(nextFree,this);
return(i);
}
};
TwoWayVectorIterator.cc
template<typename T> class TwoWayVector;
template <class T> class TwoWayVectorIterator{
public:
TwoWayVector<T>* vector;
int currentPosition;
TwoWayVectorIterator(TwoWayVector<T>& vec){
currentPosition = 0;
vector = vec;
}
TwoWayVectorIterator( int pos , TwoWayVector<T>* vec){
currentPosition = pos;
vector = vec;
}
bool operator==(const TwoWayVectorIterator* vector2){
bool contents, position;
contents = (vector == vector2) ? true : false;
cout << contents << endl;
position =(currentPosition == vector2->currentPosition) ? true : false;
return (contents && position);
}
bool& operator!=(const TwoWayVectorIterator* vector2){
bool contents, position;
contents = (vector == vector2) ? false : true;
position=(currentPosition == vector2->currentPosition) ? false : true;
return (contents || position);
}
TwoWayVectorIterator& operator++(){
return *this;
currentPosition = (currentPosition+1);
}
TwoWayVectorIterator& operator++(int){
currentPosition = (currentPosition+1);
return *this;
}
TwoWayVectorIterator& operator=(TwoWayVectorIterator* vector2){
&vector = vector2;
currentPosition = vector2->currentPosition;
return *this;
}
TwoWayVectorIterator& operator+(int n){
currentPosition = currentPosition+n;
return *this;
}
TwoWayVectorIterator& operator-(int n){
currentPosition = currentPosition-n;
return *this;
}
bool& operator<(TwoWayVectorIterator* vector2){
return (currentPosition<vector2->currentPosition);
}
T& operator*(){
return vector[currentPosition];
}
};
cout << beginning==beginning2;
does not mean
cout << (beginning==beginning2);
It does mean
(cout << beginning) == beginning2;
http://en.cppreference.com/w/cpp/language/operator_precedence
Therefore you are printing a TwoWayVectorIterator<int>*, not a bool.
The precedence of the << operator is higher then the precedence of the == and != operator. So
cout << beginning==beginning2;
cout << beginning != beginning2;
really means
(cout << beginning)==beginning2;
(cout << beginning) != beginning2;
Try
cout << (beginning==beginning2);
cout << (beginning) != beginning2);