Конструкторы std::unordered_set

Я смотрел на конструкторы unordered_set. Разве невозможно создать unordered_set с пользовательским экземпляром распределителя, БЕЗ установки количества блоков хеша? Я бы действительно не хотел связываться с деталями реализации, потому что мне нужен пользовательский распределитель, а тип не содержит определений для значения по умолчанию. MSDN дает только три перегрузки для конструктора, ни одна из которых не очень полезна.

Редактировать: Святое дерьмо. Моя STL-реализация std::hash не будет специализироваться для строк с пользовательским типом распределителя - она ​​может выполнять только явные определения типов std::string и std::wstring. Я имею в виду, я могу понять, что я не хочу пытаться хэшировать случайные строки символов, а просто потому, что у него есть собственный распределитель? Это отвратительно меня

tokens(std::unordered_set<string>().bucket_count(), std::hash<string>(), std::equal_to<string>(), stl_wrapper::hash_set<string>::allocator_type(this))
template<typename Char, typename CharTraits, typename Allocator> class std::hash<std::basic_string<Char, CharTraits, Allocator>>
    : public std::unary_function<std::basic_string<Char, CharTraits, Allocator>, std::size_t> {
public:
    size_t operator()(const std::basic_string<Char, CharTraits, Allocator>& ref) const {
        return std::hash<std::basic_string<Char, CharTraits>>()(std::basic_string<Char, CharTraits>(ref.begin(), ref.end()));
    }
};

Решает проблемы, но избыточные конструкции и копирование? Ewwwww.

2 ответа

Решение

Это странно, но вы правы. Я полагаю, что мысль о том, что поддерживать все возможные комбинации параметров со значениями по умолчанию - это излишне.

Лучший способ справиться с этим - построить пустой unordered_set со всеми настройками по умолчанию, получить из него количество сегментов по умолчанию, используя unordered_set::bucket_count, а затем используйте это как входные данные, когда вы создаете экземпляр контейнера, который вам действительно нужен.

unordered_set<int> temp;
size_t buckets = temp.bucket_count;
unordered_set<string> actual(buckets, Hash(), Pred(), 
    YourAllocator(param1 /*, etc */));

Поскольку вы пишете Allocator, имеет смысл также контролировать количество сегментов, ведь оба связаны с памятью:)

Стив дал суть метода, если вы не хотите, теперь позвольте мне предложить вспомогательную функцию:)

template <typename T>
size_t number_buckets()
{
  std::unordered_set<T> useless;
  return useless.bucket_count();
}

И с этим, маленький (простой) помощник:

template <typename T, typename Hash, typename Pred, typename Allocator>
std::unordered_set<T,Hash,Pred,Allocator>
  make_unordered_set(Hash const& hash, Pred const& pred, Allocator const& alloc)
{
  static size_t const nbBuckets = number_buckets<T>();
  return std::unordered_set<T,Hash,Pred,Allocator>(nbBuckets, hash, pred, alloc);
}

Хорошо работает с auto:

auto set = make_unordered_set<std::string>(Hash(), Pred(), Allocator(1,2,3));

Вы также можете, конечно, просто вырвать константу из вашей любимой реализации.

Другие вопросы по тегам