문제

I've been looking at the constructors of unordered_set. Is it not possible to construct an unordered_set with a custom allocator instance WITHOUT setting the number of hash buckets? I'd really rather not mess with implementation details because I want a custom allocator, and the type provides no definitions for the default value. MSDN only gives like three overloads for the constructor, none of which are terribly useful.

Edit: Holy crap. My STL implementation of std::hash won't specialize for strings with a custom allocator type- it can only do the explicit typedefs std::string and std::wstring. I mean, I can understand not wanting to try to hash random character strings, but just because it's got a custom allocator? This disgusts me.

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()));
    }
};

Solves the problems, but redundant constructions and copying? Ewwwww.

도움이 되었습니까?

해결책

That's strange, but you are right. I suppose the thought was that it's overkill to support all possible parameter combinations, with defaults.

The best way I can think to handle this is to construct an empty unordered_set with all default settings, get the default bucket count from it using unordered_set::bucket_count, and then use that as input when you instantiate the container you actually want.

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

다른 팁

Since you are writing the Allocator, it makes sense to control the number of buckets too, after all both are memory related :)

Steve gave the heart of the method if you don't want to, now let me propose a helper function :)

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

And with that, a little (simple) helper:

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);
}

Works pretty well with auto:

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

You could also, of course, simply rip the constant out of your favorite implementation.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top