For my c++ class we were given the task of writing a template class who's class object's type is defined by the user using templates.
Code snipit from main:
if (dataType == "1" || dataType == "int") {
simpleVector<int> userArray;
} else if (dataType == "2" || dataType == "double") {
simpleVector<double> userArray;
} else if (dataType == "3" || dataType == "char") {
simpleVector<char> userArray;
} else if {
simpleVector<string> userArray;
}
userArray.setDefaultArray();
From this I get error code C2065 - undeclared identifier error. I see why I am getting the error but i do not know how I can declare userArray before I know the data type.
Source Code:
#include <stdio.h>
#include <string>
using std::string;
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
template<class T>
class simpleVector {
public:
void setDefaultArray ();
void setArraySize (int size);
void copy (T *arr);
void desctruct ();
int getArraySize ();
T getElementAt (int index);
void fillArray();
private:
int arraySize;
T *myArray;
};
int main () {
string dataType;
int arraySize;
bool loopCondition = false;
do {
cout << "Data Type:";
cin >> dataType;
if (dataType == "1" || dataType == "2" || dataType == "3" || dataType == "4"
|| dataType == "int" || dataType == "double" || dataType == "char" || dataType == "string") {
loopCondition = false;
} else {
cout << "WARNING: invalid data type entered." << endl;
cout << "Valid entries are (1.int, 2.double, 3.char, 4.string)" << endl;
loopCondition = true;
}
} while (loopCondition);
if (true)
int num = 9;
else
int num = 7;
int num2 = num;
//simpleVector userArray; //?? Review
if (dataType == "1" || dataType == "int") {
simpleVector<int> userArray;
} else if (dataType == "2" || dataType == "double") {
simpleVector<double> userArray;
} else if (dataType == "3" || dataType == "char") {
simpleVector<char> userArray;
} else if (dataType == "4" || dataType == "char") {
simpleVector<string> userArray;
}
userArray.setDefaultArray();
cout << "Number of Inputs:";
cin >> arraySize;
userArray.setArraySize(arraySize);
userArray.fillArray();
return 0;
}
//Should call desctruct before this if reusing.
template<class T>
void simpleVector<T>::setDefaultArray() {
arraySize = 0;
myArray = NULL; //note: NULL is case sensitive (#include <stdio.h>)
}
template<class T>
void simpleVector<T>::setArraySize (int size) {
myArray = new T[size];
}
template<class T>
void simpleVector<T>::copy (T *arr) {
//ToDo
}
template<class T>
void simpleVector<T>::desctruct () {
//ToDo
}
template<class T>
int simpleVector<T>::getArraySize () {
//ToDo
}
template<class T>
T simpleVector<T>::getElementAt (int index) {
//ToDo
}
template<class T>
void simpleVector<T>::fillArray() {
cout << "Enter Array Values" << endl;
for (int i; i < arraySize; i++) {
cout << "Element " + i + ":";
cin >> myArray[i];
}
}
Thanks,
Mike
The code in Eugene's answer looks great, but is maybe too complicated for learning C++?
A very simple solution could look like this
declare a class vectorBase, which declares all the methods you need in all your vectors
let the templated class inherit from vectorBase
template
class simpleVector : public vectorBase { ...
then declare a pointer of type vectorBase before your
if (dataType == "1" || dataType == "int") ...
in the if-block assign the newly created userArrays to the base class pointer
later, access the methods through the baseClass pointer, which is identical for all specific template classes
You can't do this, because types determination are a compile-time process. Use inheritance instead templates, if you want to determine types at runtime.
Also I can suggest you the "variant" pattern. For example:
#include <memory>
#include <string>
class variant
{
public:
template <class T>
variant& operator = (T const& t)
{
typedef type<T> assign_type;
object = std::auto_ptr<assign_type>(new assign_type(t));
return *this;
}
template <class T>
operator T ()
{
typedef type<T> assign_type;
assign_type& type = dynamic_cast<assign_type&>(*object);
return type.get();
}
private:
class base
{
public:
virtual ~base() {}
};
typedef std::auto_ptr<base> base_ptr;
template <class T>
class type : public base
{
public:
type(T const& t)
: object(t)
{
}
T get() const
{
return object;
}
private:
T object;
};
base_ptr object;
};
struct dummy
{
int a;
int b;
int c;
};
int main()
{
variant v1, v2, v3, v4;
v1 = 2;
v2 = 5.0f;
v3 = std::string("Pot of gold");
v4 = dummy();
int i = v1;
float f = v2;
std::string s = v3;
dummy d = v4;
return 0;
}
As I understand, the intention of this problem is to teach how template usage is limited by type definition on compile time. It's pretty straightforward that user's choice will be limited by some list of types which developer cared to explicitly specify. Now the question is - how it affects the resulting program?
First, you should realize that code-paths for all possible values of your template argument will be instantiated on compile time. In other words, binary code for setDefaultArray, setArraySize, fillArray and other member functions which you explicitly or implicitly call in your generic algorithm will be generated for int, double, char and std::string template arguments. There's not much you can do to optimize it out of the executable.
However, what you can do is to decide how to store your object(s) in memory in most efficient way. And obviously for your task you need only a single instance of some simpleVector at a time. So you may think of a memory block big enough to keep any simpleVector instantiation and also designating which of them it currently contains. In C++ it will sound like this:
struct SimpleVectors {
VectorTypeEnum vte;
union {
simpleVector<int> v_int;
simpleVector<double> v_double;
simpleVector<char> v_char;
simpleVector<string> v_string;
};
};
Please note that you can do it only with POD-structures (google for the definition).
Inheritance-based approaches eventually boil-down to this kind of layout.
To complete the picture, we just need to connect a processing logic to this data structure:
template <
typename T
>
inline void handleTask (
simpleVector <
T
>
& v
)
{
int arraySize;
v.setDefaultArray();
cout << "Number of Inputs:";
cin >> arraySize;
v.setArraySize(arraySize);
v.fillArray();
}
The benefit of this approach over the inheritance-based is that you can make your class member functions inline, and the compiler will take care that their calls will be an order of magnitude faster than the virtual member functions.
And finally, the key piece of your main function will look as:
SimpleVectors userArray;
// we don't really need to initialize userArray.vte in this sample
if (dataType == "1" || dataType == "int") {
handleTask(userArray.v_int);
} else if (dataType == "2" || dataType == "double") {
handleTask(userArray.v_double);
} else if (dataType == "3" || dataType == "char") {
handleTask(userArray.v_char);
} else if (dataType == "4" || dataType == "string") {
handleTask(userArray.v_string);
}
Related
I have a template class that I am testing:
class SparseMat {
private:
FHvector<FHlist<MatNode<Object>>> matrix;
int numOfRows, numOfCols;
const Object defaultValue;
public:
SparseMat(int r, int c, const Object& defaultVal);
const Object & get(int r, int c) const;
bool set(int r, int c, const Object& x);
};
template <class Object>
SparseMat<Object>::SparseMat(int r, int c, const Object& defaultVal) : defaultValue(defaultVal) {
numOfRows = r;
numOfCols = c;
matrix.resize(numOfRows);
for (int counter = 0; counter < numOfRows; counter++) {
FHlist<MatNode<Object>> currentRow;
matrix.push_back(currentRow);
}
}
template <class Object>
bool SparseMat<Object>::set(int r, int c, const Object& x) {
if (r >= numOfRows || r < 0 || c < 0 || c >= numOfCols) {
return false;
}
if (r == 9 && c == 9) {
cout << x << endl;
}
if (r == 9 && c == 9) {
cout << x << endl;
}
for (FHlist<MatNode<Object>>::iterator iter = matrix[r].begin(); iter != matrix[r].end(); ++iter) {
if ((*iter).getCol() == c) {
if (x == defaultValue) {
matrix[r].erase(iter);
return true;
}
else {
(*iter).data = x;
return true;
}
}
}
matrix[r].push_back(MatNode<Object>(c, x));
return true;
}
template <class Object>
const Object & SparseMat<Object>::get(int r, int c) const {
if (r >= numOfRows || r < 0 || c < 0 || c >= numOfCols) {
throw OutOfBoundsException();
}
FHlist<MatNode<Object>> wantedRow = matrix[r];
for (FHlist<MatNode<Object>>::iterator iter = wantedRow.begin(); iter != wantedRow.end(); ++iter) {
if ((*iter).getCol() == c) {
return (*iter).getData();
}
}
return NULL;
}
MatNode is as follows:
template <class Object>
class MatNode
{
protected:
int col;
public:
Object data;
MatNode(int cl = 0, Object dt = Object()) : col(cl), data(dt) { }
int getCol() const { return col; }
const Object & getData() const {return data; }
};
The immensely strange thing is my two outputs print two different things. The first prints 21, as expected. The second prints out some random float, which is definitely not expected as I have changed nothing with x between the two outputs.
#include <iostream>
using namespace std;
#include "FHsparseMat.h"
#define MAT_SIZE 100000
typedef SparseMat<float> SpMat;
int main()
{
SpMat mat(MAT_SIZE, MAT_SIZE, 0);
mat.set(3, 9, 21);
cout << mat.get(3, 9) << endl;
mat.set(9, 9, 21);
cout << mat.get(9, 9) << endl;
mat.set(9, 9, mat.get(3,9));
cout << mat.get(9, 9) << endl;
}
Here is my tester. If I replace mat.get(3,9) with the hard coded value of 21, the issue disappears, if that helps.
get() has a return type of const Object &.
As a result, the final line of the function
return 0; // source code says NULL but preprocessor replaces that with 0
is returning a dangling reference to a temporary Object implicitly constructed with the value 0.
Using that dangling reference will, of course, cause undefined behavior.
It's not completely clear why that line is reached, but the logic that erases an item if you write the same value to the same location certainly seems suspicious. IMO you should only remove an item when the value written is zero.
The issue is that Object MatNode::getData() const is not returning a reference, and you are returning a reference in const Object & SparseMat<Object>::get(int r, int c) const. Change it to:
Object SparseMat<Object>::get(int r, int c) const.
I'm new to programming in C++. Also new to implementing stacks. My objective is creating RPN Calculator using template stack. Cant use the built in stack classes.
I have everything so far and now I am stuck, I can't think of how to fix this problem. I am currently getting these errors:
Error C2109 subscript requires array or pointer type
Warning C4244 'return': conversion from 'double' to 'int', possible loss of data
This is my stack class:
#include<stack>
#define STACK_MAX 500
template<class T>
class RPNCalculator
{
private:
//Insanciating stack class
T data[STACK_MAX];
int size;
//stack<T> rpnstack;
public:
RPNCalculator() {
size = 0;
}
~RPNCalculator();
int Top() {
if (size == 0) {
fprintf(stderr, "Error: stack empty\n");
return -1;
}
return data[size - 1];
}
void push(T data); // pushes a new operand onto the stack
// the following operations are to be performed as defined for Reverse Polish Notation
// binary operators:
T value(); // returns the topmost value
void pop(); // returns the topmost value and pops it off the top
double add();
double subtract();
double multiply();
double divide();
// unary operators:
double square(); // squares the current value
double negate(); // negates, i.e. 3 becomes -3
bool isEmpty(); // tests to see if there are elements on the stack
void clear(); // clears out the stack
};
template<class T>
inline bool RPNCalculator<T>::isEmpty()
{
bool status;
if (!top)
status = true;
else
status = false;
return status;
}
template<class T>
void RPNCalculator<T>::clear()
{
}
template<class T>
inline RPNCalculator<T>::~RPNCalculator()
{
}
template<class T>
inline void RPNCalculator<T>::push(T data)
{
if (size < STACK_MAX)
data[size++] = data;
else
fprintf(stderr, "Error: stack full\n");
}
template<class T>
inline T RPNCalculator<T>::value()
{
return T();
}
template<class T>
inline void RPNCalculator<T>::pop()
{
if (size == 0)
fprintf(stderr, "Error: stack empty\n");
else
size--;
}
This is my main class:
#include <iostream>
#include "RPNCalculator.h"
#include <string>
#include <sstream>
using namespace std;
bool isOperator(const string& input);
void performOperation(const string& st, RPNCalculator<double>& rpnstack);
int main() {
cout << "Welcome to the RPN Calculator by AbdulFatai Saliu __D00168401" << endl;
cout << "Enter c to clear \n"
<< "s to square \n"
<< "n to negate \n"
<< "p to pop current value \n"
<< "q to quit \n"
;
RPNCalculator<double> rnpstack;
string input;
while (true) {
//Dispaly prompt
cout << ">> ";
//get user input
cin >> input;
//check for numeric values
double numereric;
if (istringstream(input) >> numereric) {
}
else if (isOperator(input)) {
}
else if (input == "q") {
return 0;
}
else {
cout << "Input Not Valid" << endl;
}
//check for operators
//check for exit
// display invalid value message
}
system("PAUSE");
//return 0;
}
bool isOperator(const string& input) {
string operators[] = { "-","+","*","/"};
for (int i = 0; i < 6; i++) {
if (input == operators[i]) {
return true;
}
}
return false;
}
void performOperation(const string& input, RPNCalculator<double>& rpnstack) {
double firstValue, secondValue, result;
firstValue = rpnstack.Top();
rpnstack.pop();
secondValue = rpnstack.Top();
rpnstack.pop();
if (input == "-") {
result = secondValue - firstValue;
}
else if (input == "+") {
result = secondValue + firstValue;
}
else if (input == "*") {
result = secondValue * firstValue;
}
else if (input == "/") {
result = secondValue / firstValue;
}
cout << result << endl;
rpnstack.push(result);
}
the problem seems to be coming from my push() method in the RPNCalculator template class.
Looks like you have a parameter for the function void push(T data); where the parameter has the same name as the class member (data, your storage). Try changing the parameter name in the function implementation that doesn't yield this conflict. You could also be specific which data you want to use if you really want to use that name.
Try this one instead
template<class T>
inline void RPNCalculator<T>::push(T arg)
{
if (size < STACK_MAX)
data[size++] = arg;
else
fprintf(stderr, "Error: stack full\n");
}
or, if you want to be explicit about which data you are assigning
template<class T>
inline void RPNCalculator<T>::push(T data)
{
if (size < STACK_MAX)
this->data[size++] = data; // this->data is the member, data is the function local variable
else
fprintf(stderr, "Error: stack full\n");
}
This is usually avoided by naming the member variables in a way where there can't be conflicts. One way is to prefix your members with m_, where data would become m_data. Feel free to use any style of code that you want, but I'd suggest avoiding conflicts (and the second approach) when possible.
Debug Assertion Failed!
Program: ...nts\Visual Studio 2015\Projects\Project 5\Debug\Project 5.exe
File: minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp
Line: 892
Expression: is_block_type_valid(header->_block_use)
For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.
(Press Retry to debug the application)
The program runs and outputs everything correctly, and throws this error. I haven't been able to find any good explanations of what this means or how to go about finding or fixing it. Here is a complete copy of the (incredibly ugly and badly written) code:
#include <iostream>
using namespace std;
/* a class for storing a Binary Tree */
template <class Type>
class BinaryTree {
protected:
Type parentArray[10];
Type childArray[10];
public:
BinaryTree();
BinaryTree(int& k);
~BinaryTree();
BinaryTree(BinaryTree<Type>& bt);
void operator= (BinaryTree<Type>& bt);
friend ostream& operator<< (ostream& s, BinaryTree<Type> bt) {
s << "[ ";
bt.inorder(bt.getRoot());
s << "]" << endl;
return s;
};
int size();
int height();
int getLeft(int k);
int getRight(int k);
void preorder(int k);
void inorder(int k) {
// do I have a left child?
if ((getLeft(k)) != -1) {
// if yes inorder (left child)
inorder(getLeft(k));
};
// output k
cout << k << " ";
// do I have a right child?
if ((getRight(k)) != -1) {
// if yes inorder (right child)
inorder(getRight(k));
};
};
void postorder(int k);
void setRoot(Type& val);
void setParent(Type* child, Type* parent);
void setLeft(Type& val);
void setRight(Type& val);
int getRoot();
};
/* default constructor */
template <class Type>
BinaryTree<Type>::BinaryTree() {
parentArray = new ArrayClass<Type>();
childArray = new ArrayClass<Type>();
};
/* non-empty constructor */
template <class Type>
BinaryTree<Type>::BinaryTree(int& k) {
// parentArray = new Type[k];
// childArray = new Type[k];
};
template <class Type>
BinaryTree<Type>::~BinaryTree() {
delete[] parentArray;
delete[] childArray;
};
template <class Type>
BinaryTree<Type>::BinaryTree(BinaryTree<Type>& bt) {
for (int i = 0; i < bt.size(); i++) {
parentArray[i] = bt.parentArray[i];
childArray[i] = bt.childArray[i];
};
};
template <class Type>
void BinaryTree<Type>::operator= (BinaryTree<Type>& bt) {
};
/* return the size of the tree using the length of the parent array */
template <class Type>
int BinaryTree<Type>::size() {
return (sizeof(parentArray)/sizeof(*parentArray));
};
template <class Type>
int BinaryTree<Type>::height() {
return 5;
};
template <class Type>
int BinaryTree<Type>::getLeft(int k) {
// if the parent array value of the given number is k and
// the child array value indicates it is a left child
for (int i = 0; i < size(); i++) {
if ((parentArray[i] == k) && (childArray[i] == 0)) {
// return that value
return i;
};
};
return -1;
};
template <class Type>
int BinaryTree<Type>::getRight(int k) {
// if the parent array value of the given number is k and
// the child array value indicates it is a right child
for (int i = 0; i < size(); i++) {
if ((parentArray[i] == k) && (childArray[i] == 1)) {
// return that value
return i;
};
};
return -1;
};
template <class Type>
void BinaryTree<Type>::preorder(int k) {
// output k
cout << k << " ";
// do I have a left child?
if ((getLeft(k)) != -1) {
// if yes preorder left child
preorder(getLeft(k));
};
// do I have a right child?
if ((getRight(k)) != -1) {
// if yes preorder right child
preorder(getRight(k));
};
};
template <class Type>
void BinaryTree<Type>::postorder(int k) {
// do I have a left child?
if ((getLeft(k)) != -1) {
// if yes inorder (left child)
inorder(getLeft(k));
};
// do I have a right child?
if ((getRight(k)) != -1) {
// if yes inorder (right child)
inorder(getRight(k));
};
// output k
cout << k << " ";
};
template <class Type>
void BinaryTree<Type>::setRoot(Type& val) {
// if the given value is the root of the tree then set
// its index in the parent and child arrays to -1
parentArray[val] = -1;
childArray[val] = -1;
};
template <class Type>
void BinaryTree<Type>::setParent(Type* child, Type* parent) {
// set a given value as the parent of a given value
parentArray[(*child)] = *parent;
};
template <class Type>
void BinaryTree<Type>::setLeft(Type& val) {
// set a given value in the child array to indicate a left child
childArray[val] = 0;
};
template <class Type>
void BinaryTree<Type>::setRight(Type& val) {
// set a given value in the child array to indicate a right child
childArray[val] = 1;
};
template <class Type>
int BinaryTree<Type>::getRoot() {
// find the root value of the tree
for (int i = 0; i < size(); i++) {
if (parentArray[i] == -1) {
// and return it
return i;
};
};
};
int main() {
int* val1 = new int;
int* val2 = new int;
int* val3 = new int;
int count;
cin >> count;
BinaryTree<int> bt(count);
for (int i = 0; i < count; i++) {
cin >> *val1;
cin >> *val2;
cin >> *val3;
if (i == 0) {
bt.setRoot(*val1);
};
if (*val2 != -1) {
bt.setParent(val2, val1);
bt.setLeft(*val2);
}
if (*val3 != -1) {
bt.setParent(val3, val1);
bt.setRight(*val3);
}
val1 = new int;
val2 = new int;
val3 = new int;
};
cout << bt.size() << endl;
bt.postorder(bt.getRoot());
cout << endl;
bt.preorder(bt.getRoot());
cout << endl;
delete val1;
delete val2;
delete val3;
};
Some of the functions in the BinaryTree class aren't finished yet and just have filler garbage in them for testing.
Your BinaryTree destructor always makes sure to:
delete[] parentArray;
delete[] childArray;
Unfortunately, one of the class's constructors does not new any of these arrays. As such, the destructor ends up attempting to delete a pair of uninitialized garbage pointers.
It's also possible that this class violates the Rule Of The Three, but I have not analyzed this sufficiently.
EDIT: as it's been pointed out in the comments, these are not pointers; so this is wrong anyway, but for other reasons.
I'm learning about templating in C++ and I'm trying to write a template class to handle different data types in order to read a configuration text file formatted in a way similar to
TYPE,DEFAULT_VALUE
I defined the following class
template <class T>
class option_t
{
public:
option_t(std::string _type, std::string _defaultValue);
//~option_t();
std::string get_type();
T get_defaultValue();
private:
T defaultValue;
};
template <class T>
option_t<T>::option_t(std::string _type,std::string _defaultValue)
{
type = _type;
if( type.compare("integer") == 0)
{
defaultValue = std::stoi(_defaultValue);
}
else if(type.compare("real") == 0)
{
char *pEnd;
defaultValue = std::strtod(_defaultValue.c_str(),&pEnd);
}
else if( type.compare("boolean") == 0 )
{
std::transform(_defaultValue.begin(),_defaultValue.end(),_defaultValue.begin(),::tolower);
if(_defaultValue.compare("true") == 0 ||
_defaultValue.compare("1") == 0 ||
_defaultValue.compare("on") == 0)
{
defaultValue = true;
}
else
{
defaultValue = false;
}
}
else
{
//LOG(ERROR) << "Option " << name << " : unknown data type ( " << type << " )";
}
template <class T>
std::string option_t<T>::get_type()
{
return type;
}
template <class T>
T option_t<T>::get_defaultValue()
{
return defaultValue;
}
and when I use the following line into my main code
int tmpInt = option.get_defaultValue();
I get a compilation error "no viable conversion from 'std::__1::basic_string' to 'int'"
What does it mean? And how can I solve it?
Thanks and sorry for the stupid question :-)
Here all rest of my code
class options_t
{
public:
options_t();
//~options_t();
template <class T>
void set_option(option_t<T> option);
private:
};
options_t::options_t()
{
// read file and depending on _type create a specific option object
std::string _type = "integer";
std::string _defaultValue = "5";
if(_type.compare("integer") == 0)
{
option_t<int> option(_type,_defaultValue);
set_option(option);
}
else if(_type.compare("real") == 0)
{
option_t<double> option(_type,_defaultValue);
set_option(option);
}
else if(_type.compare("boolean") == 0)
{
option_t<bool> option(_type,_defaultValue);
set_option(option);
}
else if(_type.compare("string") == 0)
{
option_t<std::string> option(_type,_defaultValue);
set_option(option);
}
else
{
// LOG(ERROR) << " invalid data type( " << _type << " )";
}
}
template <class T>
void options_t::set_option(option_t<T> option)
{
std::string _type = option.get_type();
if(_type.compare("integer") == 0)
{
int tmpInt = option.get_defaultValue();
option_t<int> tmpOption(option.get_type(),defaultValue);
}
else if(_type.compare("real") == 0)
{
//todo;
}
else if(_type.compare("boolean") == 0)
{
//todo;
}
else if(_type.compare("string") == 0)
{
//todo;
}
else
{
// LOG(ERROR) << " invalid data type( " << option.get_type() << " )";
}
}
int main()
{
options_t options();
}
Depends on what you want to do. I will assume that int tmpInt is correct.
To retrieve an int, option has to be option_t<int> or option_t<T> where T is convertible to int. Look likes you're trying to use a string.
How do I pass a templated class to the constructor of another class? I am trying to pass a templated hash table class to a menu class which will allow me to then allow the user to decide the type of the hash table.
template <class T>
class OpenHash
{
private:
vector <T> hashTab;
vector <int> emptyCheck;
int hashF(string);
int hashF(int);
int hashF(double);
int hashF(float);
int hashF(char);
public:
OpenHash(int);
int getVectorCap();
int addRecord (T);
int sizeHash();
int find(T);
int printHash();
int deleteEntry(T);
};
template <class T>
OpenHash<T>::OpenHash(int vecSize)
{
hashTab.clear();
hashTab.resize(vecSize);
emptyCheck.resize(vecSize);
for (int i=0; i < emptyCheck.capacity(); i++)
{
emptyCheck.at(i) = 0;
}
}
So I have this class Open hash that is templated, because it supposed to allow for any type to be added, I have this working if initiate a object of it in my main and change input types etc.
int main ()
{
cout << "Please input the size of your HashTable" << endl;
int vecSize = 0;
cin >> vecSize;
cout << "Please select the type of you hash table integer, string, float, "
"double or char." << endl;
bool typeChosen = false;
string typeChoice;
cin >> typeChoice;
while (typeChosen == false)
{
if (typeChoice == "int" || "integer" || "i")
{
OpenHash<int> newTable(vecSize);
typeChosen = true;
}
else if (typeChoice == "string" || "s")
{
OpenHash<string> newTable(vecSize);
hashMenu<OpenHash> menu(newTable);
typeChosen = true;
}
else if (typeChoice == "float" || "f")
{
OpenHash<float> newTable(vecSize);
typeChosen = true;
}
else if (typeChoice == "double" || "d")
{
OpenHash<double> newTable(vecSize);
typeChosen = true;
}
else if (typeChoice == "char" || "c" || "character")
{
OpenHash<char> newTable(vecSize);
typeChosen = true;
}
else
{
cout << "Incorrect type";
}
}
return 0;
}
In my main I want to ask the user what type they which to make the hash table. depending what they enter it should create a instance of this class with the type they want and then pass this to another class called menu which should allow them to call functions from the hash class.
You can use:
class Ctor {
public:
Ctor(const Other<int>&); // if you know the specific type
};
or:
class Ctor {
public:
template<class T>
Ctor(const Other<T>&); // if you don't know the specific type
};
Live demo