Unable to Access Struct Members within Template - c++

I decided to make my HashTable class a template so I could practice making templates, but I've run into a problem. Within my HashTable<T> template, I have a data member array, called items of Buckets, which is a struct within the HashTable<T> class. After initializing items, I am unable to access the members of Bucket elsewhere in the template's code.
I have tried putting typename and template<class T> before the struct and variable definitions, but was unable to make it work.
Here is a snippet of code that gives me the error 'keyValue': undeclared identifier
#ifndef HASH_TABLE_
#define HASH_TABLE_
using namespace std;
#include <iostream>
template<class T>
class HashTable
{
public:
HashTable(int numItems) {
if (numItems <= 0) {
throw std::invalid_argument("Invalid HashTable size");
}
currItems = 0;
//B must be the next prime after 2 * numItems
B = 1000;
items = Bucket[B]; //allocate array of Buckets
items[0].keyVal; //ERROR: undeclared identifier
}
bool insert(T* newItem, int key) {
bool retVal = false;
if (currItems < B && newItem != NULL) { //cannot insert to full HashTable
int index = 0;
items[index].dataPtr = newItem; //ERROR:undeclared
items[index].keyVal = key; //ERROR:undeclared
retVal = true;
currItems++;
}
return retVal;
}
private:
struct Bucket {
T* dataPtr = NULL;
int keyVal = -1;
};
Bucket * items; //array of buckets
int B; //size of itemArray
int currItems; //track number of items in HashTable
};
#endif
Why does items[x] not access a Bucket, such that items[x].keyVal or items[x].dataPtr cannot be used? I've tried different types of initializations, such as items = new Bucket[B], but that hasn't worked either, so I am assuming my errors lie in the template side of things.
I appreciate any guidance!

You have to declare Bucket before you use it.
template<class T>
class HashTable
{
struct Bucket {
T* dataPtr = NULL;
int keyVal = -1;
};
public:
HashTable(int numItems) {
if (numItems <= 0) {
throw std::invalid_argument("Invalid HashTable size");
}
currItems = 0;
//B must be the next prime after 2 * numItems
B = nextPrime(numItems * 2);
items = new Bucket[B]; // <-- you forgot the 'new'
items[0].keyVal; //ERROR: undeclared identifier
}
bool insert(T* newItem, int key) {
bool retVal = false;
if (currItems < B && newItem != NULL) { //cannot insert to full HashTable
int index = getOpenBucket(key);
items[index].dataPtr = newItem; //ERROR:undeclared
items[index].keyVal = key; //ERROR:undeclared
retVal = true;
currItems++;
}
return retVal;
}
private:
Bucket * items; //array of buckets
int B; //size of itemArray
int currItems; //track number of items in HashTable
};
ps. do not do this: using namespace std; in header files - ever.
It is evil and antisocial as it poisons the global namespace of every cpp file that includes your header. It's a guaranteed way to ensure that no-one will ever use your library.

Related

Why do I keep getting a read access violation? C++

I keep running through the program and changing around pointers and I don't see what I am missing. I keep getting a read access violation on line 42 of the .cpp file and I am genuinely confused on how.
Here is the .cpp file
#include "Graph.h";
void Graph::insertEdge(int from, int to, int weight)
{
if (from <= size && to <= size)
{
bool leave = true;
EdgeNode* current = vertices[from].edgeHead;
while (leave)
{
if (from == current->adjVertex || current == nullptr) //Read access violation here
{
current->weight = weight;
if (current == nullptr)
{
current->adjVertex = to;
current->nextEdge = nullptr;
}
leave = false;
}
else
current = current->nextEdge;
}
}
}
and here is the .h file
#include "Vertex.h";
#include <fstream>;
using namespace std;
class Graph
{
static const int MAX_VERTICES = 101;
struct EdgeNode
{
int adjVertex = 0;
int weight = 0;
EdgeNode* nextEdge = nullptr;
};
struct VertexNode
{
EdgeNode* edgeHead = nullptr;
Vertex* data = nullptr;
};
struct Table
{
bool visited;
int dist;
int path;
};
public:
void buildGraph(ifstream& in);
void insertEdge(int from, int to, int weight);
void removeEdge(int beginning, int end);
void findShortestPath();
void displayAll();
void display(int begin, int end);
private:
int size;
VertexNode vertices[MAX_VERTICES];
Table T[MAX_VERTICES][MAX_VERTICES];
};
I've been on this problem for multiple hours now and I can't seem to find the issue.
Probably instead of
if (from == current->adjVertex || current == nullptr)
you should first ensure the pointer is not null before dereferencing it.
if (current == nullptr || from == current->adjVertex)
then if current is null, the right-hand side of || operator won't be run.
HOWEVER, you will still have a problem because you also dereference current->weight inside the if-statement, even if current is null.

How would I combine two ArrayLists that are of a special type?

The goal of this portion of the assignment is to create specialized implementations of an ArrayList of Addresses, or ArrayList<Address>. We are to combine two ArrayLists of this type, but our given starter code has me a bit lost on where to start.
First, we have a templated ArrayList from class in ArrayList.h, along with some functions to go with it:
template <class T>
class ArrayList {
public:
/**
* #brief Add copy of item to the end of the list, growing internal storage if needed
* #param insertItem Item to duplicate into the list
*/
void insertEnd(const T& insertItem);
/**
* YOU WILL IMPLEMENT IN AddressArrayList.h/cpp
*/
void combine(ArrayList<T>& otherList);
protected:
/**
* #brief Allocate new storage array double old capacity and copy
* existing items to it.
*/
void grow();
T* list; ///dynamic array holding stored items
int length; ///logical length of list - how many items are being stored
int maxSize; ///size of array used for storage
};
template <class T>
void ArrayList<T>::grow()
{
int newSize = maxSize * 2;
T* tempList = new T[newSize];
for(int i = 0; i < maxSize; i++)
tempList[i] = list[i];
maxSize = newSize;
delete [] list;
list = tempList;
}
template <class T>
void ArrayList<T>::insertEnd(const T& insertItem)
{
if(length == maxSize)
grow();
list[length] = insertItem;
length++;
}
After this, we have the definition of an Address in Address.h:
#ifndef ADDRESS_H
#define ADDRESS_H
#include <string>
#include <fstream>
struct Address {
std::string first;
std::string last;
std::string streetAddr;
std::string city;
std::string county;
std::string state;
int zipCode;
Address();
//Accepts comma seperated line of text with fields in order of member variables
explicit Address(const std::string& dataLine);
};
Finally, in AddressArrayList.cpp is the function we are supposed to implement. It is stated to be a "template specialization for an ArrayList of Addresses. This is defining a combine that will ONLY work for an ArrayList". My confusion begins at this point. The function should be implemented along the lines of something like listA.combine(listB), and given that fact and all the code given to us already, I think I need to use the this pointer, but what I've tried below resulted in failure, and I don't know where to go from here.
// #brief Move all items from otherList to the end of this List.
// #param otherList List to be combined into this one. It should end up empty.
template <>
void ArrayList<Address>::combine(ArrayList<Address>& otherList) {
grow();
for (int i = 0; i < this->length + otherList.length; i++) {
this->list[i + length] = otherList.list[i];
}
}
You can simply use 'insertEnd()' as NadavS suggested, but if the otherList is very long, then you may end up with calling grow() by insertEnd() multiple times, which is inefficient. To optimize this, I think you can modify grow() to increase the capacity only once.
template <class T>
void ArrayList<T>::grow(int more=0)
{
int newSize = maxSize + (more > 0 ? more : maxSize);
T* tempList = new T[newSize];
for(int i = 0; i < maxSize; i++)
tempList[i] = list[i];
maxSize = newSize;
delete [] list;
list = tempList;
}
template <>
void ArrayList<Address>::combine(ArrayList<Address>& otherList) {
grow(otherList.length);
for (int i = 0; i < this->length + otherList.length; i++) {
this->list[i + length] = otherList.list[i];
}
}

Lists in C++, Overloading methods?

Good evening guys, I'm totally new to C++ and I've been having some troubles with it.
Now, I'm trying to make a List, after a lot of undos and corrections, I found this error that I cannot solve.
#define MAXLIST 100
template <typename T>
class List {
private:
int maxList;
int last = 0;
T* List;
public:
List();
explicit List(int tam);
bool listIsFull();
void destroyList();
List<T>() {
last = -1;
maxList = MAXLIST;
list = new T[maxList];
}
List<T>(int tam) {
last = -1;
maxList = tam;
list = new T[maxList];
}
void destroyList() {
last = -1;
}
bool listIsFull() {
if(last == MAXLIST -1)
return true;
else
return false;
}
}
Both methods destroyList() and listIsFull(), in my IDE show an error like: 'Cannot be overloaded'
And both constructors show an error like: 'Does not name a type'
What is that, that i'm doing wrong?
Thank you in advance.
The way your code appeared to me, you tried to prototype your class and then provide implementation below it, I simply added correct scope and template operators.
#define MAXLIST 100
template <typename T>
class List {
private:
int maxList;
int last = 0;
T* List;
public:
List();
explicit List(int tam);
bool listIsFull();
void destroyList();
};
template<typename T>
List<T>::List<T>() {
last = -1;
maxList = MAXLIST;
list = new T[maxList];
}
template<typename T>
List<T>::List<T>(int tam) {
last = -1;
maxList = tam;
list = new T[maxList];
}
template<typename T>
void List<T>::destroyList() {
last = -1;
}
template<typename T>
bool List<T>::listIsFull() {
if (last == MAXLIST - 1)
return true;
else
return false;
}

Template Class Assignment Operator Overloading

I'm having a little trouble with the following:
I'm writing a map abstract data type for some coursework & I've come across a problem whilst trying to assign an object of my class (MapEntry - below) to an array of the same type in the class MapADT. It tells me that:
Error 1 error C2679: binary '=' : no operator found which takes a right-hand operand of type 'MapEntry *' (or there is no acceptable conversion) c:\users\cross_000\documents\visual studio 2013\projects\objectorientedmethodsasignment1\mapadt\mapadt.h 14
So I thought I would write my own Assignment operator override. I've done this in the MapEntry class definition but the compiler doesn't seem to recognize it when I try to initialize the array in the constructor on MapADT - below.
Any help would be greatly appreciated.
#pragma once
template <class Tk, class Tc>
class MapEntry
{
private:
Tk key;
Tc contents;
bool isPopulated;
public:
MapEntry() {
}
MapEntry(Tk keyInput, Tc contentsInput) {
key = keyInput;
contents = contentsInput;
isPopulated = true;
}
MapEntry(Tk keyInput, Tc contentsInput, bool isPopulatedInput) {
key = keyInput;
contents = contentsInput;
isPopulated = isPopulatedInput;
}
~MapEntry() {
//TODO
}
Tk getKey() {
return key;
}
void setKey(Tk keyInput) {
key = keyInput;
}
Tc getContents() {
return contents;
}
void setContents(Tc contentsInput) {
contents = contentsInput;
}
bool getIsPopulated() {
return isPopulated;
}
void setIsPopulated(bool isPopulatedInput) {
isPopulated = isPopulatedInput;
}
MapEntry<Tk, Tc>& operator=(const MapEntry<Tk, Tc> & lst)
{
clear();
copy(lst);
return *this;
}
};
MapADT.h
#pragma once
#include "MapEntry.h"
template <class Tk, class Tc>
class MapADT
{
private:
int mapSize = 1000;
MapEntry<Tk, Tc> *map;
public:
MapADT() {
map = new MapEntry<Tk, Tc>[mapSize];
for (int i = 0; i < mapSize; i++) {
map[i] = new MapEntry<Tk, Tc>(NULL, NULL, false);
}
}
}
There's more to the MapADT class but I don't think it's relevant. If you need to see the whole thing I can add it.
map[i] is not an pointer to MapEntry.
Not sure if you want
map[i] = MapEntry<Tk, Tc>(NULL, NULL, false);
or
MapEntry<Tk, Tc>** map;
MapADT() {
map = new MapEntry<Tk, Tc>*[mapSize];
for (int i = 0; i < mapSize; i++) {
map[i] = new MapEntry<Tk, Tc>(NULL, NULL, false);
}
}
to solve your issue.
In this line
map = new MapEntry<Tk, Tc>[mapSize];
you allocate an array of MapEntry<Tk, Tc>, and default constructors are called for all of them. There's no need in subsequent for loop at all, you should just write proper initialization in MapEntry::MapEntry(), which is currently empty.

How do you check the type of variable when using arrays?

I'm trying to create a header that uses templates and vectors that will sort an array in ascending order either numerically or alphabetically based on it's contents. However, I need to check the type o variable before organizing it,since the array can be either an int array or string array or so on. I know how to organize it, but how do I check the variable type to determine which temp to assign it to? Here's what I have:
template <class T>
void SortableVector<T>::sort()
{
int temp1 = 0;
double temp2 = 0;
float temp3 = 0;
string temp4 = "";
if (this->operator[](0) //is an int
{
temp1 = this->operator[](0);
}
else if (this->operator[](0) //is a double
{
temp2 = this->operator[](0);
}
else if( this->operator[](0) //is a float
{
temp3 = this->operator[](0);
}
else if (this->operator[](0) //is a string
{
temp4 = this->operator[](0);
}
for (int count = 0; count < this->size(); count++)
{
}
}
You want to use function specialization here:
template<typename T>
class SortableVector {
private:
T* _internal;
/* ... */
public:
void sort();
};
template<typename T>
void SortableVector<T>::sort() {
/* sort a general unknown type */
}
template<>
void SortableVector<bool>::sort() {
/* sort bools */
}
template<>
void SortableVector<int>::sort() {
/* sort ints */
}
/* etc. */