Properly overloading [bracket] operator for hashtable get and set - c++

I am trying to implement a hashtable class. The problem I am facing atm is how to properly overload the square bracket operators so that getting the value at a key from the hashtable is distinguishable from setting a key to a value.
So far here is what the class looks like:
template <typename K, typename V>
class HashTable {
typedef pair<K, V> KeyVal;
avl_tree <KeyVal> **TABLE;
unsigned TABLESIZE;
public:
HashTable( const unsigned & );
V& operator [] ( const K& ); //Setter
const V& operator [](const K&) const; //Getter
typedef unsigned (*hashtype)(const K&);
static hashtype Hash;
~HashTable();
};
And this is the implementation of each overload of the brackets:
template <typename K, typename V>
V& HashTable<K, V>::operator [] ( const K& ret ) {
unsigned index = HashTable<K, V>::Hash(ret) % TABLESIZE;
avl_tree <KeyVal> *ptr = AVL_TREE::find(TABLE[index], KeyVal(ret, 0));
if ( ptr == None ) ptr = (TABLE[index] = AVL_TREE::insert(TABLE[index], KeyVal(ret, 0)));
return ptr->data.second;
}
template <typename K, typename V>
const V& HashTable<K, V>::operator [](const K& ret) const {
avl_tree <KeyVal> *ptr = AVL_TREE::find(TABLE[HashTable<K, V>::Hash(ret) % TABLESIZE], KeyVal(ret, 0));
if (ptr == None) throw "Exception: [KeyError] Key not found exception.";
return ptr->data.second;
}
Now if I do:
cout << table["hash"] << "\n"; //table declared as type HashTable<std::string, int>
I get an output of 0, but I want it to use the getter implementation of the overloaded square brackets; i.e. this should throw an exception. How do I do this?

The usual way to handle this situation is to have operator[] return a proxy.
Then, for the proxy overload operator T approximately as you've done your const overload above. Overload operator= about like your non-const version.
template <typename K, typename V>
class HashTable {
typedef pair<K, V> KeyVal;
avl_tree <KeyVal> **TABLE;
unsigned TABLESIZE;
template <class K, class V>
class proxy {
HashTable<K, V> &h;
K key;
public:
proxy(HashTable<K, V> &h, K key) : h(h), key(key) {}
operator V() const {
auto pos = h.find(key);
if (pos) return *pos;
else throw not_present();
}
proxy &operator=(V const &value) {
h.set(key, value);
return *this;
}
};
public:
HashTable( const unsigned & );
proxy operator [] ( const K& k) { return proxy(*this, k); }
typedef unsigned (*hashtype)(const K&);
static hashtype Hash;
~HashTable();
};
You basically have two cases when you use this:
some_hash_table[some_key] = some_value;
value_type v = some_hash_table[some_key];
In both cases, some_hash_table[some_key] returns an instance of proxy. In the first case, you're assigning to the proxy object, so that invokes the proxy's operator=, passing it some_value, so some_value gets added to the table with key as its key.
In the second case, you're trying to assign an object of type proxy to a variable of type value_type. Obviously that can't be assigned directly -- but proxy::operator V returns an object of the value type for the underlying Hashtable -- so the compiler invokes that to produce a value that can be assigned to v. That, in turn, checks for the presence of the proper key in the table, and throws an exception if its not present.

When equivalent const and non-const overloads of a member function or operator are available, the non-const is chosen when the method is called on a non-const instance. The const overload will only be picked if the instance is const, or if it is accessed via a const reference or pointer:
struct Foo
{
void foo() {}
void foo() const {}
};
void bar(const Foo& f) { f.foo();}
void baz(const Foo* f) { f->foo(); }
int main()
{
Foo f;
f.foo(); // non-const overload chosen
bar(f); // const overload chosen
bar(&f); // const overload chosen
const Foo cf; // const instance
cf.foo(); // const overload chosen
const Foo& rf = f; // const reference
rf.foo(); // const overload chosen
}

Related

Obtaining a pointer-to-member from addresses of an object and its member

I'm looking to reverse the .* operator.
When I have a pointer I can dereference it with * and then from dereferenced value go back to the pointer by & operator.
With pointer-to-member I can dereference it with .* operator (supplying the object instance) but there is no operator to obtain the original pointer-to-member from object and its dereferenced field.
Consider the following data structure:
struct Point { double x, y, z; };
Now I need to get a pointer to member double Point::* from (Point&, double&) pair, where that double & is a field of the Point& object.
In other words I need a function to_member_ptr such that:
template<typename DataType, typename Member>
constexpr Member DataType::* obtain_member_ptr(const DataType &that, const Member &fieldInThat);
int main(int, char*[]) {
Point pt;
static_assert(obtain_member_ptr(pt, pt.x) == &Point::x, "error");
static_assert(obtain_member_ptr(pt, pt.y) == &Point::y, "error");
static_assert(obtain_member_ptr(pt, pt.z) == &Point::z, "error");
}
I could write it by hand for given datatype as below:
constexpr double Point::* obtain_member_ptr(const Point &that, const double &fieldInThat) {
if(&that.x == &fieldInThat) return &Point::x;
if(&that.y == &fieldInThat) return &Point::y;
if(&that.z == &fieldInThat) return &Point::z;
return nullptr;
}
But it seems like a plain boilerplate and I feel that there should be a way to make compiler do that for me.
How can I portably obtain a pointer to object from object and its field?
Using visit_struct, you may first add reflection:
struct Point { double x, y, z; };
VISITABLE_STRUCT(Point, x, y, z);
Then visit your struct:
template <typename C, typename T>
struct MemberPtrGetter
{
constexpr MemberPtrGetter(const C& c, const T& field) : c(c), field(field) {}
// Correct type, check reference.
constexpr void operator() (const char* name, T C::*member) const
{
if (&(c.*member) == &field)
{
res = member;
}
}
// other field type -> ignore
template <typename U> constexpr void operator() (const char* , U C::*member) const {}
const C& c;
const Member& field;
Member C::* res = nullptr;
};
template<typename C, typename T>
constexpr T C::* obtain_member_ptr(const C& c, const T& field)
{
MemberPtrGetter<C, T> visitor{c, field};
visit_struct::apply_visitor<C>(visitor);
return visitor.res;
}

unordered_map with custom key compiler error

I have a question regarding the std::unordered_map and a custom class as it's key.
I think some background is required first:
The custom class is a variant data type, which implements basic numerical types and the std::string class.
Recently a bro of mine told me that it would be nice if the class supported arrays and hashtables. "Say no more" I thought and started implementing the array functionality (using std::vector) which works really great and then I implemented the hashmap functionality (using unordered_map<Variant, Variant>).
If I understand it right the hash function (or operator() respectively) for the unordered_map has to comply to the signature size_t (*) (const Key_Type &k) const; which my specialized version of the std::hash<Variant> object should do, shouldn't it?
In addition the unordered_map needs to check Key_Type for equality, which should be possible via operator==(), am I correct?
Anyway I'm getting a load of beautiful compiler errors of which this is, in my opinion, the most helpful:
/usr/include/c++/4.9/bits/hashtable_policy.h:85:33: error: no match for call to ‘(const std::hash<Variant>) (const Variant&)’
I really don't understand what's going on and would be really grateful for any insights in what's going on.
Below is a stripped down header of the class Variant, I hope enough information is included (to be honest I fear it's too much information but I was not sure what could be omitted).
But I left out most of the implementation details since the problem seems to occur only in the specialized hash object.
Well this is the stripped down version of the Variant header:
class Variant
{
private:
enum Type {NONE = 0, LONG, DOUBLE, STRING, ARRAY, HASH_MAP};
using Var = struct Var
{
union
{
int64_t l;
double d;
std::string *s;
std::vector<Variant> *v;
std::unordered_map<Variant, Variant> *h;
};
Type type = NONE;
};
public:
//constructors, destructor and clear function
Variant() : var() {}
Variant(long val): Variant(){var.type = LONG; var.l = val;}
Variant(double val) : Variant(){var.type = DOUBLE; var.d = val;}
Variant(const std::string &val) : Variant(){var.type = STRING; var.s = new std::string(val);}
template<typename T, typename... Args>Variant(T val, Args... args) : Variant() {set(val, args...);} //constructs an array
Variant(const Variant &val); //calls default constructor as well
Variant(Variant &&val) : Variant() {swap(*this, val);}
~Variant(){clear();}
void clear();
//set functions
template<typename T, typename... Args> void set(const T val, Args... args){if(var.type == ARRAY)var.v->clear();add(val, args...);}
void set(long val);
void set(double val);
void set(const std::string &val);
void set(const Variant &val);
//add functions
template<typename T> void add(const T val){add(Variant(val));}
template<typename T, typename... Args> void add(const T val, Args... args){add(Variant(val)); add(args...);}
void add(const std::string &val){add(Variant(val));}
void add(const Variant &val);
//array access and evaluation functions
Variant& operator[](const Variant &idx);
size_t size() const {if(var.type == ARRAY)return var.v->size(); return 0;}
std::unordered_map<Variant, Variant>::iterator begin(){if(var.type == HASH_MAP)return var.h->begin(); throw Exception("The internal type does not support iterators");}
//operator= definitions
template<typename T> Variant& operator=(const T val){set(val); return *this;}
Variant& operator=(const std::string &val){set(val); return *this;}
Variant& operator=(Variant val){swap(*this, val); return *this;}
//operator definitions
Variant& operator+=(const Variant &right);
//and operator-=, ^= etc etc...
//friend definitions (mainly comparison operators)
friend void swap(Variant &left, Variant &right); //simple swap function
friend bool operator==(const Variant &left, const Variant &right);
friend bool operator!=(const Variant &left, const Variant &right);
friend std::hash<Variant>;
private:
Var var;
};
template <typename T>
inline void hash_combine(std::size_t& seed, const T &v)
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
namespace std
{
template<> struct hash<Variant>
{
size_t operator()(const Variant &x) const
{
if(x.var.type == Variant::DOUBLE)
return std::hash<double>()(x.var.d);
else if(x.var.type == Variant::LONG)
return std::hash<int64_t>()(x.var.l);
else if(x.var.type == Variant::STRING)
return std::hash<std::string>()(*x.var.s);
else if(x.var.type == Variant::ARRAY)
{
size_t seed = 0;
for(size_t i = 0; i < x.var.v->size(); ++i)
hash_combine(seed, x.var.v->operator[](i));
return seed;
}
else if(x.var.type == Variant::HASH_MAP)
{
size_t seed = 0;
for(auto it = x.var.h->begin(); it != x.var.h->end(); ++it)
{
hash_combine(seed, it->first);
hash_combine(seed, it->second);
}
return seed;
}
else if(x.var.type == Variant::NONE)
return 0;
else
throw std::runtime_error("This Variant cannot be hashed");
}
};
}
inline void swap(Variant &left, Variant &right){Variant::Var tmp(left.var); left.var = right.var; right.var = tmp;}
bool operator==(const Variant &left, const Variant &right);
bool operator!=(const Variant &left, const Variant &right);
The problem here is that you use unordered_map<Variant, Variant> inside the definition of Variant itself. At this point your hash specialization is not available yet, that's why the compiler produces the error. You cannot just move hash definition before Variant definition because the hash needs access to Variant members. What you can do, is to separate declaration and definition of your hash:
class Variant;
namespace std
{
template<> struct hash<Variant>
{
size_t operator()(const Variant & x) const;
};
}
class Variant {
/* Variant definition goes here ... */
};
template <typename T>
inline void hash_combine(std::size_t& seed, const T &v)
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
size_t std::hash<Variant>::operator()(const Variant &x) const
{
/* hash function implementation here ... */
}
But then you have another problem: inside Variant class definition the Variant itself is incomplete type. In your union you store only pointers to vector and unordered_map, this is OK, but the begin method (actually, specification of its return type already) requires an instantiation of the unordered_map<Variant, Variant> which is not possible at that place.
(Note: Limited support for containers of incomplete types (only vector, list, and forward_list) will be added to C++17)
To solve this second problem, you can have a map member function instead of begin function which gives access to the internal map:
std::unordered_map<Variant, Variant> & map()
{
if (var.type == HASH_MAP)
return *var.h;
throw Exception("The internal type does not support iterators");
}
Then instead of
Variant v;
v.begin();
you would use
v.map().begin();

Returning reference to temporary error when remodeling from T ** to vec<vec<T>>

I encountered an error that happend in my proxy class for operator []. It was checking if index is in range, and worked fine when I implemented my class template with T** values.
But I felt like change whole implementation to std::vector<std::vector<T>>. Everything is fine, expect said operator[].
Matrix class operator(s)
//***************************************************************************
template <typename T>
X_Proxy<T> Matrix<T>::operator [](const size_t& j)
{
if(j >= y)
ERROR_MSG(Y_OUT_RANGE);
return X_Proxy<T>(inner[j], x);
}
//***************************************************************************
template <typename T>
const X_Proxy<T> Matrix<T>::operator [](const size_t& j) const
{
if(j >= y)
ERROR_MSG(Y_OUT_RANGE);
return X_Proxy<T>(inner[j], x);
}
//***************************************************************************
Proxy class template definition:
template <typename T>
struct X_Proxy
{
X_Proxy(std::vector<T> PTR, const size_t X) : x_ptr(PTR), x(X) {}
T& operator [] (size_t pos);
const T& operator [] (size_t pos) const;
std::vector<T>& x_ptr;
const size_t& x;
};
Proxy class operator(s):
//***************************************************************************
template <typename T>
T& X_Proxy<T>::operator [] (size_t pos)
{
if (pos > x-1)
Matrix<T>::ERROR_MSG(Matrix<T>::X_OUT_RANGE);
return x_ptr[pos];
}
//***************************************************************************
template <typename T>
const T& X_Proxy<T>::operator [] (size_t pos) const
{
if (pos > x-1)
Matrix<T>::ERROR_MSG(Matrix<T>::X_OUT_RANGE);
return x_ptr[pos]; // <--- the error line
}
//***************************************************************************
Matrix error function:
template <typename T>
void Matrix<T>::ERROR_MSG(const int& MSG)
{
std::cerr << info[MSG] << std::endl;
exit(MSG);
}
Compilation error:
..\matrix.h:47: error: returning reference to temporary [-Wreturn-local-addr]
return x_ptr[pos];
^
What could go wrong with our lovely template library?
Your X_Proxy constructor is storing a reference to a temporary:
X_Proxy(std::vector<T> PTR, const size_t X) : x_ptr(PTR), x(X) {}
Here, PTR is a local temporary, and x_ptr is an lvalue reference:
std::vector<T>& x_ptr;
This isn't standard C++, so it shouldn't even compile. But your compiler allows it, leaving you with a dangling reference.
Perhaps you want to store a reference to a valid vector:
X_Proxy(std::vector<T>& PTR, const size_t X) : x_ptr(PTR), x(X) {}
^
This will work as long as the vector referred to by PTR outlives the X_Proxy instance.

unordered_set storing elements as pointers

To narrow it down: I'm currently using Boost.Unordered. I see two possible solutions:
Define my own Equality Predicates and Hash Functions and to utilize templates (maybe is_pointer) to distinct between pointers and instances;
Simply to extend boost::hash by providing hash_value(Type* const& x) as for hashing; and add == operator overload as free function with (Type* const& x, Type* const& y) parameters as for equality checking.
I'm not sure whether both variations are actually possible, since I didn't test them. I would like to find out you handle this problem. Implementations are welcome :)
EDIT 1:
What about this?
template<class T>
struct Equals: std::binary_function<T, T, bool> {
bool operator()(T const& left, T const& right) const {
return left == right;
}
};
template<class T>
struct Equals<T*> : std::binary_function<T*, T*, bool> {
bool operator()(T* const& left, T* const& right) const {
return *left == *right;
}
};
EDIT 2:
I've just defined:
friend std::size_t hash_value(Base const& base) {
boost::hash<std::string> hash;
return hash(base.string_);
}
friend std::size_t hash_value(Base* const& base) {
return hash_value(*base);
}
And then:
Derived d1("x");
Derived d2("x");
unordered_set<Base*> set;
set.insert(&d1);
assert(set.find(&d2) == end());
Debugger says that friend std::size_t hash_value(Base* const& base) is never called (GCC 4.7). Why is that?
EDIT 3:
I found out that template <class T> std::size_t hash_value(T* const& v) in boost/functional/hash.hpp on line #215 (Boost 1.49) is Boost's specialization for pointers and it simply masks your custom implementation of hash_value such as mine in EDIT 2.
Therefore, it seems like the only way here is to create a custom Hash Functor.
For the hash function, you have a choice between specializing boost::hash (or std::hash in the newer standard) or defining a new functor class. These alternatives work equally well.
For the equality operator, you need to define a new functor, because you cannot redefine the equality operator over pointers. It's a built-in operator (defined in functional terms as bool operator==( T const *x, T const *y )) and cannot be replaced.
Both of these can be defined generically by using a templated operator() in a non-templated class.
struct indirect_equal {
template< typename X, typename Y >
bool operator() ( X const &lhs, Y const &rhs )
{ return * lhs == * rhs; }
};
Follow a similar pattern for the hasher.
Taking into consideration all edits in the original post I would like to provide complete solution which satisfies my needs:
1. Equality:
template<class T>
struct Equal: ::std::binary_function<T, T, bool> {
bool operator()(T const& left, T const& right) const {
::std::equal_to<T> equal;
return equal(left, right);
}
};
template<class T>
struct Equal<T*> : ::std::binary_function<T*, T*, bool> {
bool operator()(T* const & left, T* const & right) const {
Equal<T> equal;
return equal(*left, *right);
}
};
2. Hashing:
template<class T>
struct Hash: ::std::unary_function<T, ::std::size_t> {
::std::size_t operator()(T const & value) const {
::boost::hash<T> hash;
return hash(value);
}
};
template<class T>
struct Hash<T*> : ::std::unary_function<T*, ::std::size_t> {
::std::size_t operator()(T* const & value) const {
Hash<T> hash;
return hash(*value);
}
};
So now I can continue using Boost's hash_value and it will not get masked for pointer types by Boost's default implementation (see EDIT 3).
3. Example:
In my application I have a thin wrapper for unordered_set which now looks like that:
template<class T, class H = Hash<T>, class E = Equal<T> >
class Set {
public:
// code omitted...
bool contains(const T& element) const {
return s_.find(element) != end();
}
bool insert(const T& element) {
return s_.insert(element).second;
}
// code omitted...
private:
::boost::unordered::unordered_set<T, H, E> s_;
};
So if we have some base class:
class Base {
public:
Base(const ::std::string& string) {
if (string.empty())
throw ::std::invalid_argument("String is empty.");
string_ = string;
}
virtual ~Base() {
}
friend bool operator==(const Base& right, const Base& left) {
return typeid(right) == typeid(left) && right.string_ == left.string_;
}
friend bool operator!=(const Base& right, const Base& left) {
return !(right == left);
}
friend ::std::size_t hash_value(Base const& base) {
::boost::hash<std::string> hash;
return hash(base.string_);
}
friend ::std::size_t hash_value(Base* const& base) {
return hash_value(*base);
}
private:
::std::string string_;
};
And some derived class:
class Derived: public Base {
public:
Derived(const ::std::string& string) :
Base(string) {
}
virtual ~Derived() {
}
};
Then we can even use polymorphism (which was my primary intention BTW):
Derived d1("¯\_(ツ)_/¯");
Derived d2("¯\_(ツ)_/¯");
Set<Base*> set;
set.insert(&d1);
assert(set.contains(&d2));
Hope this helps. Any suggestions are welcome.

Overload comparison operators for a templated class

I'm having troubles in overloading comparison operators in order to compare two pair struct in such way:
typedef pair<string, unsigned int> INDEX;
bool operator>(INDEX &v1, INDEX &v2)
{
if(v1.second == v2.second) //if integer parts are equal
{
//string that comes earlier in the dictionary should be larger
return v1.first < v2.first;
}
return v1.second > v2.second;
}
The actual comparison takes place at this->element(hole/2) < this->element(hole) inside fixUp(CBTNODE hole), a member function of BinaryHeap class, which is a derived class of CompleteBinaryTree. The T will be instantiated as type INDEX, which is typedefed as pair<string, unsigned int>.
In other words, the comparison between two pairs: ("a.txt", 42) > ("b.txt", 42) should return true.
I tried to overload operator> outside the class declaration in two different ways but neither of them worked:
bool operator>(INDEX &v1, INDEX &v2);
bool operator>(BinaryHeap<T> &v1, BinaryHeap<T> &v2);
Any help will be much appreciated!
Z.Zen
Here is the declarations:
typedef int CBTNODE;
template <typename T>
class CompleteBinaryTree {
public:
//Initializes an empty binary tree
CompleteBinaryTree(int initialSize = 10);
//Destructor
~CompleteBinaryTree();
//Returns the element of the CBT pointed to by node. Behavior is undefined
//if node does not exist.
T element(CBTNODE node);
protected:
T *data;
int numElts, maxElts;
};
typedef pair<string, unsigned int> INDEX;
template <typename T>
class BinaryHeap : public CompleteBinaryTree<T>
{
public:
//Maintain heap property with bottom up heapify method.
void fixUp(CBTNODE hole);
};
bool operator>(INDEX &v1, INDEX &v2);
Implementation:
template <typename T>
T CompleteBinaryTree<T>::element(CBTNODE node) {
assert(node >= 0);
assert(node < numElts);
return data[node];
}
template <typename T>
void BinaryHeap<T>::fixUp(CBTNODE hole)
{
T tmp = this->element(hole);
while( hole > 0 && this->element(hole/2) < tmp )
{
//do stuff
}
}
bool operator>(INDEX &v1, INDEX &v2)
{
if(v1.second == v2.second) //if two have same relevance
{
return v1.first < v2.first;
}
return v1.second > v2.second;
}
A temporary, such as the result of element func, cannot be bound to a reference to non-const, such as the formal arguments of your operator>.
Declare it thusly:
bool operator>( INDEX const& v1, INDEX const& v2 )
However, the implementation that you present doesn't seem to be correct for operator>.
And while I'm at it, what you want is really operator< instead, because that's the one required by standard algorithms. Perhaps combined with an operator== (because it's inefficient to synthesize it from operator<). With those two any relationship can be checked for relatively efficiently.
Btw., if you stop using ALL UPPERCASE names for anything else then macros (see the FAQ), then you can avoid inadvertent name collision with macros.
Cheers & hth.,
Don't typedef INDEX, be explicit:
template<class F, class S>
struct Index {
std::pair<F, S> Value;
Index(const std::pair<F, S>& pValue)
: Value(pValue) {}
};
template<class F, class S>
bool operator<(const Index<F, S>& pLeft, const Index<F, S>& pRight) {
// your implementation...
}