Converting a class interface into a class template - c++

I'm working through some old exam papers without the memos. I just want to make sure I am understanding this correctly.
Provide an interface of the template class
Dictionary <Tkey, TValue>
This is the scenario provided
class Dictionary {
public:
Dictionary();
void Add(int key, const string &value);
string Find (int key) const;
private:
vector<int> Keys;
vector <string> Values;
};
This is the solution I have written down
class Dictionary {
public:
Dictionary();
void Add(TKey key, const TValue &value);
TValue Find (TKey key) const;
private:
vector <Dictionary> Keys;
vector <Dictionary> Values;
};
This appears correct to me. I haven't compiled a driver program for this as I just want to make sure I am understand this correctly given the template class.
I think just the last 2 lines where vector is concerned is what I want to make sure I've written correctly.
Thanks for taking the time.

You should simply follow your instructions:
template<typename Tkey, typename TValue> // <<<<<<<<
class Dictionary {
public:
Dictionary();
void Add(TKey key, const TValue &value);
TValue Find (TKey key) const;
private:
vector <TKey> Keys; // <<<<<<<<
vector <TValue> Values; // <<<<<<<
};
Or even better (since it's going to be hard to associate those vector members appropriately):
template<typename Tkey, typename TValue> // <<<<<<<<
class Dictionary {
public:
Dictionary();
void Add(TKey key, const TValue &value);
TValue Find (TKey key) const;
private:
vector <std::pair<TKey,TValue>> dict; // <<<<<<<
};

This conversion is incomplete, and slightly incorrect.
To make it complete, make sure the class is actually a class template, i.e. there is
template <typename TKey, typename TValue>
class Dictionary {
...
};
The correction is to make the two vectors take keys and values. Currently, both vectors are set to store Dictionary elements, which is not what you need: the first vector should hold TKey elements, while the second one should hold TValues. You would discover this shortcoming as soon as you'd start implementing your Dictionary<TKey,TValue>::Find method.

Related

Multidimensional map template accessed and assigned inside of class method

I was wondering if this was a valid way to assign a multidimensional map inside of a class method and if not how would I go about doing this.
template<typename T>
std::map<std::string, std::map<std::string, T>> MT;
template<typename T>
void MonsterTemplate(std::string name, std::string node, template T v) {
MT[name][node] = v;
}
Edit1: I compiled and it gave me many errors but I will just give a portion of the 1st.
error C3376: 'MonsterType::MT': only static data member templates are allowed
Edit2:
I tried creating a struct
template<typename T>
struct Wrapper
{
typedef std::map<std::string, std::map<std::string, T>> MT;
};
I then added this inside the class
template<typename T>
Wrapper<T>::MT mt;
template<typename T>
void MonsterTemplate(std::string name, std::string node, template T v) {
mt[name][node] = v;
}
Then got this error amongst many others.
warning C4346: 'MT': dependent name is not a type
The struct works outside the class without being multidimensional map, but I am unsure how to access it as multidimensional map.. just trying different things.
The idea is I want to store data of several objects data and index them by name, node and value.
Edit3:
So this is what I went with, and haven't gotten an error (just yet :p)
std::map<std::string, std::map<std::string, int>> MT;
void MonsterTemplate(std::string name, std::string node, int v) {
MT[name][node] = v;
}
Just updating this for anyone looking for something similar
So I figured out how to construct this.
template<typename T>
struct Test
{
std::map<std::string, std::map<std::string, std::map<size_t, std::map<std::string, T>>>> testmap;
void MonsterTemplate(std::string creatureName, std::string name, std::string node, T v) {
size_t i = testmap[creatureName][name].size();
testmap[creatureName][name][i][node] = v;
}
};
Test<std::string> str;
Since I needed various data types for T the structure worked much better than trying to find a way to assign a template to a static class, I am only using std::string as an example.
This can then be used inside of the class's method since str has a global scope.
str.MonsterTemplate(creatureName, name, node, value);

Compile error when using std::hash; does not name a template type

I am receiving the error
"hashmap.hpp:63:14: error: ‘hash’ in namespace ‘std’ does not name a
template type std::hash hash;"
I don't understand why i need to implement my own specialization when I'm passing in type T, which will probably be one of the types that works for the hash function.
hashmap.hpp
#ifndef __HASHMAP_HPP__
#define __HASHMAP_HPP__
#define INITIAL_CAPACITY 10
#include <iostream>
#include <functional>
// A simple node struct for your separate chaining
// You may change this if you want
template <class K,class V>
struct KVNode
{
K key;
V value;
KVNode<K,V>* next;
KVNode(KVNode<K,V>* theNext = NULL) :
next(theNext)
{
}
};
template <class K, class V>
class HashMap {
public:
// Default constructor: creates an empty hash map
HashMap();
// Constructor setting the default value for our map
HashMap(V value);
// Destructor: deallocates all memory associated
// with the hash map
~HashMap();
// size() returns the number of elements currently
// stored in the hash map.
unsigned int size() const;
// set() inserts the given key value pair into the
// hash map. If the key is already in the map, then
// the value for that key is overwritten.
void set(const K& key, const V& value);
// get() returns the value associated with the key.
// If the key is not in the hash map, the default
// value should be returned.
V get(const K& key) const;
private:
// You are allowed to add any private variables you
// need to implement the functionality of a hash map
// It is also okay to add addional public or private
// methods you need, but you may not change the
// already existing method signatures.
// You may find these private members useful, but you are
// not required to use them.
KVNode<K,V>** map;
// To use this hash map with your own key type,
// you may need to provide a specialization of std::hash.
//std::hash<K> hash; #this was previous declaration but caused error
std::hash<K> hash;
// This is the default value to return if a key is not
// in the hash map
V default_value;
};
template <class K, class V>
HashMap<K,V>::HashMap() : default_value()
{
KVNode<K,V>** map = new KVNode<K,V>*[INITIAL_CAPACITY];
for (int i = 0; i < INITIAL_CAPACITY; ++i)
map[i] = new KVNode<K,V>();
}
template <class K, class V>
HashMap<K,V>::HashMap(V value)
{
//TODO: Implement this method
}
template <class K, class V>
HashMap<K,V>::~HashMap()
{
//TODO: Implement this method
}
template <class K, class V>
unsigned int HashMap<K,V>::size() const
{
//TODO: Implement this method
}
template <class K, class V>
void HashMap<K,V>::set(const K& key, const V& value)
{
//TODO: Implement this method
}
template <class K, class V>
V HashMap<K,V>::get(const K& key) const
{
//TODO: Implement this method
}
#endif // __HASHMAP_HPP__
temp.cpp
#include "hashmap.hpp"
#include <iostream>
#include <string>
#include <functional>
using namespace std;
int main()
{
HashMap<string,int> hm = HashMap<string,int>();
return 0;
}
std::hash was introduced from C++11, you need C++11 supporting for using it.
If you work with GCC, you need to add the compilation option -std=c++11.

Custom comparator for custom class, just like STL

I have a custom class Binary search Tree. I want to pass a comparator class as an argument (with default being std::less). Most of the answers I searched use the STL objects and then pass their custom comparators. I want something different.
// Tree class
template <class T,class Compare = less<T>>
class Tree
{
struct TreeNode
{
T data;
struct TreeNode * left;
struct TreeNode * right;
};
public:
void insert(T);
};
// Custom comparator class
template <class T>
class CustomCompare
{
public:
bool compare(const T&, const T &);
};
template<class T>
bool CustomCompare<T>::compare(const T & a, const T &b)
{
cout << "calling custom comparator";
return a<b;
}
// inserting in tree
template<class T,class Compare>
void Tree<T,Compare>::insert(T val)
{
// HOW DO I CALL COMPARE HERE? I tried this
if (compare(val->data , treeNode->data)) /// does not work.
// I get error - use of undeclared identifier compare.
//IF I DO THIS, I get error - expected unqualified id
Compare<T> x; // cannot create instance of Compare
// IF I DO THIS< I can create instance of Compare but cannot call function compare.
Compare x;
x.compare(....) -- Error no member named compare in std::less
}
I cannot make the CustomCompare::compare static as I want the code to work for std::less too.
I hope the question is clear.
Note: I know I can overload operator < for the classes that will be using it. I am preparing for the situation in case source code of those classes is not available
std::less has the following function to compare objects.
bool operator()( const T& lhs, const T& rhs ) const;
If you want to use a custom compare class to be an equal substitute, you have to have such a function in that class too.
Then, you would use it as:
if (compare()(val->data , treeNode->data))

typeid() Object-Oriented Design Alternative

I have the following class using 3 different maps: keys are always strings, while values may be strings, integers or floats.
class MyMaps
{
public:
template<typename T> void addKey(const std::string& key);
void addValue(const std::string& key, const std::string& value);
void addValue(const std::string& key, int value);
void addValue(const std::string& key, float value);
private:
std::map<std::string, std::string> stringFields;
std::map<std::string, int> intFields;
std::map<std::string, float> floatFields;
};
The addValue() functions simply add a new pair to the related map. What I'm working on is the addKey() template function:
/** Add only a key, the related value is a default one and is specified by template parameter T. */
template<typename T>
void MyMaps::addKey(const string& key)
{
if (typeid(T) == typeid(string))
{
stringFields.insert(pair<string, string>(key, string()));
}
else if (typeid(T) == typeid(int))
{
intFields.insert(pair<string, int>(key, int()));;
}
else if (typeid(T) == typeid(float))
{
floatFields.insert(pair<string, float>(key, float()));
}
}
Basically, I'm using template and typeid() because I don't like this alternative that relies on type-within-function-name:
void MyMaps::addStringKey(const string& key)
{
stringFields.insert(pair<string, string>(key, string()));
}
void MyMaps::addIntKey(const string& key)
{
intFields.insert(pair<string, int>(key, int()));
}
void MyMaps::addFloatKey(const string& key)
{
floatFields.insert(pair<string, float>(key, float()));
}
The first addKey() version seems working, but I'm wondering if there is a more elegant solution. Maybe I'm missing some Object-Oriented design concept that could be helpful in this case?
Thanks in advance.
This is a perfect fit for template specialization:
template<>
void MyMaps::addKey<string>(const string& key)
{
stringFields.insert(pair<string, string>(key, string()));
}
template<>
void MyMaps::addKey<int>(const int& key)
{
intFields.insert(pair<string, int>(key, int()));;
}
template<>
void MyMaps::addKey<float>(const float& key)
{
floatFields.insert(pair<string, float>(key, float()));
}
EDIT: For syntax/more info about template specialization read: Template Specialization and Partial Template Specialization
Or better yet, if boost is an option and if the keys are unique for all 3 maps and you have 3 different maps just to be able to store them, then consider using boost::variant:
typedef boost::variant<string, int, float> ValueType;
class MyMap
{
public:
typedef std::map<std::string, ValueType> MapType;
template<typename T> void addKey(const std::string& key, T &val)
{
ValueType varVal= val;
allFields.insert(MapType::value_type(key, varVal));
}
private:
MapType allFields;
};
Your question inquires 2 things:
The real question, crafting a key value Map or Dictionary, using different types, for the values, in the same collection.
And, a potential solution, applying the "typeid" function.
More reference about "typeid":
http://en.cppreference.com/w/cpp/language/typeid
Object (and Class) Orientation is great, but, sometimes you may want to mix it with other paradigms.
What about "pointers" ?
Pointers allow different types, to be treated as the same simple type.
What about a Key Value Dictionary Collection, that stores a string key, and a pointer value, and the pointer may be integer, string, or object.
Or to be more specific. the "Value" may be a tuple, where the first field (maybe an enumerated type), indicates the real type of the value. And, the second field of the "Value" is a pointer or variant to the real field.
The first suggestion using "Unions" (a.k.a. "variants"), no pointers:
#include <string>
#include <typeinfo>
union ValueUnion
{
int AsInt,
float AsFloat,
std::string& AsStr
};
struct ValueType
{
std::type_info Id,
ValueUnion Value
};
class MyMaps
{
public:
template<typename T> void addKey(const std::string& key);
void addValue(const std::string& key, const std::string& value);
void addValue(const std::string& key, int value);
void addValue(const std::string& key, float value);
private:
std::map<std::string, ValueType> Fields;
};
Or, with pointers:
#include <string>
#include <typeinfo>
struct ValueType
{
std::type_info Id,
void* Value
};
class MyMaps
{
public:
template<typename T> void addKey(const std::string& key);
void addValue(const std::string& key, const std::string& value);
void addValue(const std::string& key, int value);
void addValue(const std::string& key, float value);
private:
std::map<std::string, ValueType> Fields;
};
I have seen this "pattern" several times, I called the "Key-Value-Type" collection.
Note: Not many experience with the STL, are you sure "std::map",
is the right collection ?
Just my 2 cents.
Might not be what you want because it's a different approach but you could use a map of variants. you can define a boost::variant to hold only string,int or float.
eladidan beat me to it and I don't know how to delete answers.

how to initialize private members of class in c++

Hi i have a c++ class with some private members as follows
template <typename V, typename E>
class Vertex
{
public:
Vertex();
~Vertex();
typedef std::pair<int, E> edgVertPair;
typedef std::vector<edgeVertPair> vectEdges;
void setVertexID(int data);
int getVertexID();
void setEdgeVertPair(int vertID, E edge);
edgVertPair getEdgeVertPair();
void setEdgeList(edgeVertPair edgeVert);
vectEdges getEdgeList();
private:
int vertexID;
edgVertPair evp;
vectEdges edgeList;
};
Now i want to create a pair i.e. something like
evp.first="someint";
evp.second="somestring";
and then push this evp into the edgeList i.e. edgeList.push_back(evp);
Now the problem is in the setter function i did something like this:
template<typename V, typename E>
void Vertex<V, E>::setEdgeVertPair(int vertID, E edge){
...populate evp;...
}
now i don't know how to populate the evp pair with vertID, edge.
Use std::make_pair to populate the evp pair.
http://www.cplusplus.com/reference/std/utility/make_pair/
Thanks to all who replied to my question, i figured it out after some search. one way was i removed the typedef's and in my private data section, declared the variables directly as
std::pair<int, E> evp;
std::vector<std::pair<int, E>> edgeList;
and that worked fine.
the other way was i had to prepend the keyword 'typename' before typedef's and it worked.