Проблема создания конструктора хэш-таблицы C++

Я делаю класс хэш-таблицы xhash<_Traits>, где класс _Traits - это структура, содержащая информацию о том, какие типы у ключа, значений, аллокатора, компаратора и является ли таблица мультитаблицей (т.е. можно ли класть несколько значений с одинаковым ключём). По сути делаю аналог xhash из std.

Немного информации о таблице, чтобы я смог полностью описать проблему:

  • От этой таблицы можно наследоваться с определённым классом _Traits, тем самым создавая контейнеры, использующие хэш-таблицу (по типу unordered_set, unordered_multiset, unordered_map и т.д.)
  • В моей таблице есть также итераторы, которые по сути являются итераторами списка, в котором хранятся все ключи со значениями.
  • Помимо списка, в таблице хранится вектор итераторов на элементы, по которому я получаю доступ к цепочкам.

И специально для случая, если хэш-таблица используется для множества, где ключ и значение - один и тот же тип, и в котором нельзя менять хранящиеся там объекты пользователю через итераторы (иначе структура поломается) я написал следующее:

using iterator = std::conditional_t<std::is_same_v<key_type, value_type>, 
                 typename _Mylist::const_iterator, typename _Mylist::iterator>;

т.е. если ключ и значение имеют один и тот же тип, то вместо итератора используется константный итератор.

А теперь сама проблема: в конструкторе по умолчанию мне приходится писать такую конструкцию:

xhash() : _List(), _Vec(_List.end()) {}

т.к. у итераторов нет конструктора по умолчанию. Но что если у меня итераторы константные? Тогда мне нужно передавать не end(), а cend(). Я пытался решить эту проблему с помощью std::enable_if_t:

template<class = std::enable_if_t< std::is_same_v<iterator, const_iterator> > >
xhash() : _List(), _Vec(default_size, _List.cend()) {}
template<class = std::enable_if_t< !std::is_same_v<iterator, const_iterator> > >
xhash() : _List(), _Vec(default_size, _List.end()) {}

Но это решение не подходит, т.к. у меня получается два конструктора одинакового приоритета. Как тогда эту проблему решить?


Ответы (2 шт):

Автор решения: AR Hovsepyan

Если я вас правильно понял, можно присваивать в теле конструктора (да, иногда нужно использовать и его тело(:).

xhash() 
{
    if constexpr (std::is_same_v<key_type, value_type>)
    {
        _Vec = _List.cend();
    }
    else
        _Vec = _List.end();
}
→ Ссылка
Автор решения: nyekitka

Нашёл здесь два выхода:

  1. Добавить конструктор по умолчанию итераторам. Оказывается в STL итераторы имеют конструкторы по умолчанию и они, видимо, создают итератор с nullptr. Тогда если у итератора есть конструктор по умолчанию, то можно написать так:
xhash() : _List(), _Vec(default_size, iterator()) {}
  1. Сконструировать вектор по умолчанию, а потом сделать resize. На это решение навёл меня @AR Hovsepyan. Когда вектор создаётся, он не создаёт никаких объектов, его массив - это nullptr, поэтому ошибки не возникнет. А потом сделать resize с заполнением объектом:
xhash() : _List(), _Vec() {
    if constexpr(std::is_same_v<key_type, value_type>)
        _Vec.resize(default_size, _List.cend());
    else _Vec.resize(default_size, _List.end());
}
→ Ссылка