Q:

Error with iterator relation operator (Custom HashTable w/ Separate Chaining and Iterators)

So, I'm creating a custom hash table with separate chaining and I wanted to implement iterators for the container as well. When finally using them, I get an error when trying to use the != operator between two iterators of the same container.
The table is of the following format: vector<list<pair<K,V>>>
Would there be an even easier way to visit all elements (Since that is what I am attempting)?
I've spent a fair amount of time looking up where I may have gone wrong but I am simply not seeing it. Does anyone understand why I am getting this error? I would greatly appreciate any assistance.
Iterator Implementation for Hash Table
  class iterator{
    friend class HashSeparateChaining;
  public:
   iterator() { } // nada

   iterator(HashSeparateChaining *tp, bool end) : table(tp) {
     if(end){
       curr_node = table->the_lists_.back().end();
       vectorPos = table->the_lists_.size()-1;
     }else{
       curr_node = table->the_lists_.at(0);
       vectorPos = 0;
       while(curr_node == table->the_lists_.at(vectorPos).end() && vectorPos < table->the_lists_.size()){
         ++vectorPos;
         curr_node = table->the_lists_.at(vectorPos);
       }
     }
   }

   iterator operator++(){
     while(curr_node == table->the_lists_.at(vectorPos).end() && vectorPos < table->the_lists_.size()){
       ++vectorPos;
       curr_node = table->the_lists_.at(vectorPos);
     }
     return *this;
   }

   iterator operator++(int unusedVal){
     iterator old = *this;
     ++(*this);
     return old;
   }

   iterator operator==(const iterator &other) const {
     return table == other.table && vectorPos == other.vectorPos && curr_node == other.curr_node;
   }

   iterator operator!=(const iterator &other) const {
     return !(this == other);
   }

   pair<Key, Value> operator*() {
     return *curr_node;
   }

   pair<Key, Value>* operator->() {
     return &(*curr_node);
   }

  private:
   HashSeparateChaining *table;
   int vectorPos;
   typename list<pair<Key, Value>>::iterator curr_node;
  };

  class const_iterator {
    friend class HashSeparateChaining;
  public:
    const_iterator () { }

    const_iterator(HashSeparateChaining *tp, bool end) : table(tp) {
      if(end){
        curr_node = table->the_lists_.back().end();
        vectorPos = table->the_lists_.size()-1;
      }else{
        curr_node = table->the_lists_.at(0);
        vectorPos = 0;
        while(curr_node == table->the_lists_.at(vectorPos).end() && vectorPos < table->the_lists_.size()){
          ++vectorPos;
          curr_node = table->the_lists_.at(vectorPos);
        }
      }
    }

    bool operator==(const const_iterator& other) const{
      return table == other.table && vectorPos == other.vectorPos && curr_node == other.curr_node;
    }

    bool operator!=(const const_iterator& other) const{
      return !(*this == *other);
    }

    const_iterator& operator++(){
      while(curr_node == table->the_lists_.at(vectorPos).end() && vectorPos < table->the_lists_.size()){
        ++vectorPos;
        curr_node = table->the_lists_.at(vectorPos);
      }
      return *this;
    }

    const_iterator operator++(int){
      iterator old = *this;
      ++(*this);
      return old;
    }

    pair<Key, Value> operator*() const{
      return *curr_node;
    }

    pair<Key, Value>* operator->() const{
      return &(*curr_node);
    }

  private:
   HashSeparateChaining *table;
   int vectorPos;
   typename list<pair<Key, Value>>::const_iterator curr_node;
  };

  /**********************     END OF ITERATOR CLASS     **********************/
  iterator begin() {
    return iterator(this, false);
  }

  iterator end() {
    return iterator(this, true);
  }

  const_iterator cbegin() {
    return iterator(this, false);
  }

  const_iterator cend() {
    return iterator(this, true);
  }

where code crashes
HashSeparateChaining<int,vector<string>> wordsByLength;
for( auto & str : words )
    wordsByLength[ str.length( ) ].push_back( str );
for ( auto s1 = wordsByLength.begin(), e1 = wordsByLength.end(); s1 != e1; ++s1 ){
    const vector<string> & groupsWords = s1->second;
    int groupNum = s1->first;
    for( int i = 0; i < groupNum; ++i ){
        HashSeparateChaining<string,vector<string>> repToWord;
        for( auto & str : groupsWords ){
            string rep = str;
            rep.erase( i, 1 );
            repToWord[ rep ].push_back( str );
        }
        for ( auto s2 = repToWord.begin(), e2 = repToWord.end(); s2 != e2; ++s2 ){
            const vector<string> & clique = s2->second;
            if( clique.size( ) >= 2 )
                for( int p = 0; p < clique.size( ); ++p )
                    for( int q = p + 1; q < clique.size( ); ++q ){
                        hash_table[ clique[ p ] ].push_back( clique[ q ] );
                        hash_table[ clique[ q ] ].push_back( clique[ p ] );
                    }
        }
    }
}

compiler error
test_hash_map.cc:35:67: error: value of type 'HashSeparateChaining<int, std::__1::vector<std::__1::basic_string<char>,
      std::__1::allocator<std::__1::basic_string<char> > > >::iterator' is not contextually convertible to 'bool'
        for ( auto s1 = wordsByLength.begin(), e1 = wordsByLength.end(); s1 != e1; ++s1 ){
                                                                         ^~~~~~~~
test_hash_map.cc:46:63: error: value of type 'HashSeparateChaining<std::__1::basic_string<char>,
      std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > > >::iterator' is not
      contextually convertible to 'bool'
                        for ( auto s2 = repToWord.begin(), e2 = repToWord.begin(); s2 != e2; ++s2 ){

Actual Hash Table implementation
#ifndef SEPARATE_CHAINING_H
#define SEPARATE_CHAINING_H

#include <iostream>
#include <vector>
#include <list>
#include <iterator>
#include <string>
#include <algorithm>
#include <functional>
#include <utility>
using namespace std;

#include "is_prime.h"

// SeparateChaining Hash table class
//
// CONSTRUCTION: an approximate initial size or default of 101
//
// ******************PUBLIC OPERATIONS*********************
// bool insert( x )       --> Insert x
// bool remove( x )       --> Remove x
// bool contains( x )     --> Return true if x is present
// void makeEmpty( )      --> Remove all items

template <typename Key, typename Value>
class HashSeparateChaining {
 public:
  // always initil size of 101
  explicit HashSeparateChaining(int size = 101) : current_size_{0} {
    the_lists_.resize( 101 ); }

  ~HashSeparateChaining(){
    MakeEmpty();
  }

  bool Contains( const Key & given_key ) const {
    // iterator pointing to front of the list that the item should belong to
    auto & corresponding_list = the_lists_[ MyHash( given_key.first ) ];
        return find( begin( corresponding_list ), end( corresponding_list ), given_key ) != end( corresponding_list );
  }

  void MakeEmpty( ) {
    // clear every list in the vector
    for( auto & curr_list : the_lists_ )
      curr_list.clear( );
  }

  bool Insert( const pair<Key, Value> & given_pair ) {
    // iterator pointing to front of the list that the item should be pushed to
    auto & corresponding_list = the_lists_[ MyHash( given_pair.first ) ];

    // try to find item in corresponding_list
    // IF ITEM IS ALREADY THERE RETURN FALSE
    if( find( begin( corresponding_list ), end( corresponding_list ), given_pair ) != end( corresponding_list) )
      return false;

    // ELSE INSERT ITEM TO BACK OF LIST
    corresponding_list.push_back( given_pair );
    // Rehash; see Section 5.5
    if( ++current_size_ > the_lists_.size( ) )
      Rehash( );

    return true;
  }

  bool Insert( pair<Key, Value> && given_pair) {
    // iterator pointing to front of the list that the item should be pushed to
    auto & corresponding_list = the_lists_[ MyHash( given_pair.first ) ];

    // try to find item in corresponding_list
    // IF ITEM IS ALREADY THERE RETURN FALSE
    if( find( begin( corresponding_list ), end( corresponding_list ), given_pair ) != end( corresponding_list ) )
      return false;

    // ELSE INSERT ITEM TO BACK OF LIST
    corresponding_list.push_back( std::move( given_pair ) );
    // Rehash; see Section 5.5
    if( ++current_size_ > the_lists_.size( ) )
      Rehash( );

    return true;
  }

  bool Remove( const Key & given_key ) {
    // where item should be if present
    auto & corresponding_list = the_lists_[ MyHash( given_key ) ];
    // iterator pointing to location of obj, or @ end if not present
    auto itr = find( begin( corresponding_list ), end( corresponding_list ), given_key );

    if( itr == end( corresponding_list ) )
      return false;

    corresponding_list.erase( itr );
    --current_size_;
    return true;
  }

  Value& operator[](Key given_key){
    auto & corresponding_list = the_lists_[ MyHash( given_key ) ];
    for(auto &curr_pair : corresponding_list)
      if(curr_pair.first == given_key)
        return curr_pair.second;
    // if item not currently in container
    corresponding_list.push_back(make_pair(given_key, Value()));
    return corresponding_list.back().second;
  }

  /********************     START OF ITERATOR SUPPORT     ********************/
  class iterator{
    friend class HashSeparateChaining;
  public:
   iterator() { } // nada

   iterator(HashSeparateChaining *tp, bool end) : table(tp) {
     if(end){
       curr_node = table->the_lists_.back().end();
       vectorPos = table->the_lists_.size()-1;
     }else{
       curr_node = table->the_lists_.at(0);
       vectorPos = 0;
       while(curr_node == table->the_lists_.at(vectorPos).end() && vectorPos < table->the_lists_.size()){
         ++vectorPos;
         curr_node = table->the_lists_.at(vectorPos);
       }
     }
   }

   iterator operator++(){
     while(curr_node == table->the_lists_.at(vectorPos).end() && vectorPos < table->the_lists_.size()){
       ++vectorPos;
       curr_node = table->the_lists_.at(vectorPos);
     }
     return *this;
   }

   iterator operator++(int unusedVal){
     iterator old = *this;
     ++(*this);
     return old;
   }

   iterator operator==(const iterator &other) const {
     return table == other.table && vectorPos == other.vectorPos && curr_node == other.curr_node;
   }

   iterator operator!=(const iterator &other) const {
     return !(this == other);
   }

   pair<Key, Value> operator*() {
     return *curr_node;
   }

   pair<Key, Value>* operator->() {
     return &(*curr_node);
   }

  private:
   HashSeparateChaining *table;
   int vectorPos;
   typename list<pair<Key, Value>>::iterator curr_node;
  };

  class const_iterator {
    friend class HashSeparateChaining;
  public:
    const_iterator () { }

    const_iterator(HashSeparateChaining *tp, bool end) : table(tp) {
      if(end){
        curr_node = table->the_lists_.back().end();
        vectorPos = table->the_lists_.size()-1;
      }else{
        curr_node = table->the_lists_.at(0);
        vectorPos = 0;
        while(curr_node == table->the_lists_.at(vectorPos).end() && vectorPos < table->the_lists_.size()){
          ++vectorPos;
          curr_node = table->the_lists_.at(vectorPos);
        }
      }
    }

    bool operator==(const const_iterator& other) const{
      return table == other.table && vectorPos == other.vectorPos && curr_node == other.curr_node;
    }

    bool operator!=(const const_iterator& other) const{
      return !(*this == *other);
    }

    const_iterator& operator++(){
      while(curr_node == table->the_lists_.at(vectorPos).end() && vectorPos < table->the_lists_.size()){
        ++vectorPos;
        curr_node = table->the_lists_.at(vectorPos);
      }
      return *this;
    }

    const_iterator operator++(int){
      iterator old = *this;
      ++(*this);
      return old;
    }

    pair<Key, Value> operator*() const{
      return *curr_node;
    }

    pair<Key, Value>* operator->() const{
      return &(*curr_node);
    }

  private:
   HashSeparateChaining *table;
   int vectorPos;
   typename list<pair<Key, Value>>::const_iterator curr_node;
  };

  /**********************     END OF ITERATOR CLASS     **********************/
  iterator begin() {
    return iterator(this, false);
  }

  iterator end() {
    return iterator(this, true);
  }

  const_iterator cbegin() {
    return iterator(this, false);
  }

  const_iterator cend() {
    return iterator(this, true);
  }
  /*********************     END OF ITERATOR SUPPORT     *********************/

 private:
  vector<list<pair<Key, Value>>> the_lists_;
  int  current_size_;

  void Rehash( ) {
    vector<list<pair<Key, Value>>> old_lists = the_lists_;

    // Create new double-sized, empty table
    the_lists_.resize( PrimeProject::NextPrime( 2 * the_lists_.size( ) ) );
    for( auto & curr_list : the_lists_ )
      curr_list.clear( );

    // Copy table over
    current_size_ = 0;
    for( auto & curr_list : old_lists )
      for( auto & item_in_list : curr_list )
         insert( std::move( item_in_list ) );
  }

  size_t MyHash( const Key & given_key ) const {
    static hash<Key> hf;
    return hf( given_key ) % the_lists_.size( );
  }
};

#endif

A:

I think you made a mistake when implementing the operators == and != for your iterator : the return type you put is iterator when it should be bool.
iterator operator==(const iterator &other) const {
 return table == other.table && vectorPos == other.vectorPos && curr_node == other.curr_node;
}

iterator operator!=(const iterator &other) const {
 return !(this == other);
}

An interesting note from http://en.cppreference.com/w/cpp/language/operator_comparison
Where built-in operators return bool, most user-defined overloads also return bool so that the user-defined operators can be used in the same manner as the built-ins. However, in a user-defined operator overload, any type can be used as return type (including void).

