   }
 };
 
-template< typename tuple_of_vectors >
+template< typename tuple_of_vectors, 
+          int... cols>
 struct TestParameters
 {
+
+  static_assert((std::tuple_size<tuple_of_vectors>::value >= sizeof...(cols)), 
+      "The number of columns to hash must be less than or equal to the total number of columns.");
+
   // The tuple of vectors that determines the number and types of the columns 
   using multi_column_t = tuple_of_vectors;
+
+  constexpr static const int num_cols_to_hash{sizeof...(cols)};
+
+  // The columns that will be hashed to determine the partitions
+  constexpr static const std::array<int, sizeof...(cols)> cols_to_hash{{cols...}};
+  //constexpr static const std::vector<size_t> cols_to_hash{{cols...}};
 };
 
 

template <class test_parameters>
struct HashPartitionTest : public testing::Test
{

  // multi_column_t is a tuple of vectors. The number of vectors in the tuple
  // determines the number of columns, and the value_type of each
  // vector determines the data type of the column
  using multi_column_t = typename test_parameters::multi_column_t;
  multi_column_t the_columns;

  // Containers for unique_ptrs to gdf_columns 
  // unique_ptrs are used to automate freeing device memory
  std::vector<gdf_col_pointer> gdf_columns;

  // Containers for the raw pointers to the gdf_columns
  std::vector<gdf_column*> raw_gdf_columns;

  HashPartitionTest()
  {

  void create_input( size_t num_rows, size_t max_value,
                     bool print = false)
  {
    initialize_tuple(input_columns, num_rows, max_value);
    initialize_tuple(output_columns, num_rows, max_value);

    gdf_input_columns = initialize_gdf_columns(input_columns);
    gdf_output_columns = initialize_gdf_columns(output_columns);

    // Fill vector of raw pointers to gdf_columns
    for(auto const& c : gdf_input_columns){
      this->raw_gdf_input_columns.push_back(c.get());
      this->raw_gdf_output_columns.push_back(c.get());
    }

    if(print)
    {
      std::cout << "Input column(s) created. Size: " 
                << std::get<0>(input_columns).size() << std::endl;
      print_tuple(input_columns);
    }
  }

  void compute_gdf_result(const int num_partitions, bool print = false)
  {
    const int num_columns = std::tuple_size<multi_column_t>::value;

    gdf_error result_error{GDF_SUCCESS};

    gdf_column ** gdf_input_columns = raw_gdf_input_columns.data();
    gdf_column ** gdf_output_columns = raw_gdf_output_columns.data();

    std::vector<int> partition_offsets(num_partitions,0);

    result_error = gdf_hash_partition(num_columns, 
                                      gdf_input_columns,
                                      this->cols_to_hash.data(),
                                      this->num_cols_to_hash,
                                      num_partitions,
                                      gdf_output_columns,
                                      partition_offsets.data(),
                                      GDF_HASH_MURMUR3);

    EXPECT_EQ(GDF_SUCCESS, result_error);

