   return the_column;
 }
 
+// Each element of the result will be an index into the left and right columns where
+// left_columns[left_index] == right_columns[right_index]
+struct result_type 
+{
+  size_t left_index{};
+  size_t right_index{};
+
+  result_type(size_t _l, size_t _r) : 
+    left_index{_l}, right_index{_r} {}
+
+  // Overload comparison so the result vector can be sorted
+  bool operator <(result_type const& rhs){
+    return( std::tie(left_index, right_index) < std::tie(rhs.left_index, rhs.right_index) );
+  }
+
+  friend std::ostream& operator<<(std::ostream& os, const result_type& result);
+
+};
+
+// Overload the stream operator to make it easier to print a result 
+std::ostream& operator<<(std::ostream& os, const result_type& result)
+{
+  os << result.left_index << ", " << result.right_index << std::endl;
+  return os;
+}
+
 // A new instance of this class will be created for each *TEST(JoinTest, ...)
 // Put all repeated setup and validation stuff here
 template <class T>
-struct LeftJoinTest : public testing::Test
+struct InnerJoinTest : public testing::Test
 {
 
   // Extract the types for the input columns 

    if(num_columns >= 2){
      auto const & second_left_column = std::get<1>(left_columns);
      auto const & second_right_column = std::get<1>(right_columns);

      if(second_left_column[left_index] != second_right_column[right_index]){
        match = false;
      }

    }

    if(num_columns >= 3){
      auto const & third_left_column = std::get<2>(left_columns);
      auto const & third_right_column = std::get<2>(right_columns);

      if(third_left_column[left_index] != third_right_column[right_index])
      {
        match = false;


  multi_column_t right_columns;


  InnerJoinTest()
  {
    static size_t number_of_instantiations{0};

