2

I want to create an open hash table. And i want to use an array of lists, where the size of the array is a template parameter, but the problem is i don't know how to pass an allocator to all of the list instances, and i cannot use vector, because i will need another allocator for list allocation (alloception), is there a way to initialize a whole array of lists with the same value? I know i can initialize like this list<int> mylist[] = {{allocator}, {allocator}, {allocator}}

But the idea is to have size as a template variable. Example:

template<typename KEY, typename VAL, typename ALLOC=std::allocator<struct _internal>, size_t TBL_SIZE=100>
class open_hash_table{
private: 
   std::list<struct _internal, ALLOC=ALLOC> _table[TBL_SIZE];
public: 
    open_hash_table(ALLOC allocator=ALLOC())
    :_table({allocator, allocator ... allocator}){}
};

P.s. my compiler supports upto c++11

MrHarmz
  • 23
  • 4
  • Since the table size is rather large (100), I think a loop is better than aggregate initialization. – Raymond Chen Mar 09 '22 at 14:45
  • If you can afford it, the easiest way would be to just default construct elements and then [`std::fill()`](https://en.cppreference.com/w/cpp/algorithm/fill) (or [`.fill()`](https://en.cppreference.com/w/cpp/container/array/fill) for `std::array`) it with elements constructed with allocators. Otherwise, you'd probably need to wrap `std::list` with some class that will default-construct `list` with your allocator. – Yksisarvinen Mar 09 '22 at 14:47
  • You can create storage array for lists, and then initialize all the lists there using placement new. – user7860670 Mar 09 '22 at 14:51
  • You can create a initializer list recursively with vardiac templates. It's really ugly. My suggesti9on would be to get a newer compiler. This is so much simpler with more modern c++. – Goswin von Brederlow Mar 09 '22 at 18:05

2 Answers2

2

This uses C++14 for std::make_index_sequence and the std::index_sequence it produces but you can make your own implementation as shown here. Using a delegating constructor you can add another constructor that takes an index_sequence so you can then expand the sequence and get a variadic list of values like

template<typename KEY, typename VAL, typename ALLOC=std::allocator<struct _internal>, size_t TBL_SIZE=100>
class open_hash_table{
private: 
    std::list<struct _internal, ALLOC> _table[TBL_SIZE];
    template <std::size_t... Is>
    open_hash_table(ALLOC allocator, std::index_sequence<Is...>) 
    : _table{ std::list<struct _internal, ALLOC>{((void)Is, allocator)}... } {}
public: 
    open_hash_table(ALLOC allocator=ALLOC())
    : open_hash_table(allocator, std::make_index_sequence<TBL_SIZE>{}) {}
};

Your public constructor will call the private helper constructor and pass along an index_sequence that will have TBL_SIZE number of elements in it. Then in the delegating constructor the ((void)Is, allocator) part uses the comma operator to use each element of the index_sequence but we discard that in instead let the expression resolve to allocator. The (void)Is part casts the result of Is to void to suppress that it is unused. We have to use std::list<struct _internal, ALLOC>{ ... } as well because the constructor that takes an allocator is explicit so the type needs to be specified, no implicit conversion allowed.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
0

It is possible to initialize _table directly in member initializer lists through some metaprogramming techniques, but since TBL_SIZE's default value is 100, this will make the compile-time overhead slightly larger. It is more appropriate to just default construct _table and initializes its value in the constructor body.

And since TBL_SIZE is a compile-time constant, instead of using a raw array, you can just use std::array:

template<typename KEY, typename VAL, typename ALLOC=std::allocator<_internal>, size_t TBL_SIZE=100>
class open_hash_table{
private:
  std::array<std::list<_internal, ALLOC>, TBL_SIZE> _table;
public:
  open_hash_table(ALLOC allocator=ALLOC()) {
    _table.fill(std::list<_internal, ALLOC>(allocator));
  }
};

Also since this is C++, the struct keyword in struct _internal is unnecessary.

康桓瑋
  • 33,481
  • 5
  • 40
  • 90