C++ std::无序的_集构造函数

C++ std::无序的_集构造函数,c++,unordered-set,C++,Unordered Set,我一直在研究无序集合的构造函数。在不设置哈希桶数的情况下,是否可以使用自定义分配器实例构造无序的_集?我真的不想弄乱实现细节,因为我想要一个自定义分配器,并且该类型没有为默认值提供定义。MSDN只为构造函数提供了三个重载,没有一个是非常有用的 编辑:天哪。我的std::hash的STL实现不会专门用于具有自定义分配器类型的字符串-它只能执行显式的typedefs std::string和std::wstring。我的意思是,我可以理解不想尝试散列随机字符串,但仅仅因为它有一个自定义分配器?这让我

我一直在研究无序集合的构造函数。在不设置哈希桶数的情况下,是否可以使用自定义分配器实例构造无序的_集?我真的不想弄乱实现细节,因为我想要一个自定义分配器,并且该类型没有为默认值提供定义。MSDN只为构造函数提供了三个重载,没有一个是非常有用的

编辑:天哪。我的std::hash的STL实现不会专门用于具有自定义分配器类型的字符串-它只能执行显式的typedefs 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()));
    }
};
令牌(std::无序集().bucket\u count(),std::hash(),std::equal\u to(),stl\u包装器::hash\u集::分配器类型(this))
模板类std::hash
:公共标准::一元函数{
公众:
size\u t运算符()(常量std::basic\u string&ref)常量{
返回std::hash()(std::basic_字符串(ref.begin(),ref.end());
}
};

解决了问题,但重复构造和复制?EWWWW.

这很奇怪,但你是对的。我认为支持所有可能的参数组合(带有默认值)有点过分了

我能想到的处理这个问题的最好方法是使用所有默认设置构造一个空的
unordered\u集
,使用
unordered\u集::bucket\u count
从中获取默认的bucket count,然后在实例化实际需要的容器时将其用作输入

unordered_set<int> temp;
size_t buckets = temp.bucket_count;
unordered_set<string> actual(buckets, Hash(), Pred(), 
    YourAllocator(param1 /*, etc */));
无序设置温度;
大小桶=温度桶计数;
无序_设置实际值(存储桶、散列()、Pred(),
您的分配器(param1/*等*/);

既然您正在编写
分配器,那么控制存储桶的数量也是有意义的,毕竟两者都与内存有关:)

Steve给出了方法的核心,如果您不想,现在让我提出一个助手函数:)


当然,你也可以简单地从你最喜欢的实现中删除常量。

如果我的自定义分配器不能默认构造,我就不能这么做。@Steve:因为YourAllocator()是一个编译错误,因为没有默认构造函数。对,但关键是你在第二次调用中传入了你想要的分配器,将其他参数设置为其默认值。对不起,我的话太多了,我一定是漏掉了什么。您不能将
yourlocator
构造函数作为param 4进行sub吗?@DeadMG-是的,但是第一次调用的目的只是确定实现的默认桶计数。然后丢弃容器。默认的分配器没有问题。@Steve:你完全正确。我没有考虑过构建一个不同类型的无序集合。现在我只需要说服我的散列实现,无论我选择如何分配所述字符串,它都会进行相同的散列
std::hash
有点欠缺,特别是我认为标准应该提供一个函数来散列字节序列,以便更容易专门化UDT(包括自定义分配器的字符串)。但是,由于交替分配的字符串与任何强制的
散列
专门化都不相关,因此您很快就看不到任何帮助。好吧,你只需要选择你自己的散列算法,然后写一个专门化,或者为你的容器指定散列。@Steve:不完全是。基本的字符串构造函数可以接受任何迭代器,因此实际上扩展它使其成为不依赖于分配器的并不十分困难,但它涉及到一个冗余副本,这使我很生气。@DeadMG:是的,这取决于您使用自定义分配器的原因。如果您想让程序中的所有分配都通过分配器,那么它不仅仅是一个冗余副本,而是完全失败。@DeadMG:事实上,我可能只是没有完成我的家庭作业。有
std::collate::hash
,因此您可能可以执行
命名空间std{template struct hash{typedef size\u t result\u type;typedef basic\u string参数\u type;result\u type操作符()(const参数\u type&str){return collate::hash(str.begin(),str.end())}
。只是打个电话就有点啰嗦…@史蒂夫:你为什么这么说?现在,来自每个所属对象的所有非托管分配都在这里进行,但全局分配挂钩无法知道所属对象。不,控制两者都没有意义,因为一个控制分配了多少内存,另一个控制算法的实现细节,而另一个只测量它。这两者根本没有必然的联系。
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 set = make_unordered_set<std::string>(Hash(), Pred(), Allocator(1,2,3));