Проблема создания конструктора хэш-таблицы 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 шт):
Если я вас правильно понял, можно присваивать в теле конструктора (да, иногда нужно использовать и его тело(:).
xhash()
{
if constexpr (std::is_same_v<key_type, value_type>)
{
_Vec = _List.cend();
}
else
_Vec = _List.end();
}
Нашёл здесь два выхода:
- Добавить конструктор по умолчанию итераторам. Оказывается в STL итераторы имеют конструкторы по умолчанию и они, видимо, создают итератор с
nullptr. Тогда если у итератора есть конструктор по умолчанию, то можно написать так:
xhash() : _List(), _Vec(default_size, iterator()) {}
- Сконструировать вектор по умолчанию, а потом сделать 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());
}