我有一个使用字符串类型作为键的unordered_map
:
std::unordered_map<string, value> map;
为string
提供了std::hash
专门化,以及适当的operator==
。
现在我还有一个"string view“类,它是一个指向现有字符串的弱指针,避免了堆分配:
class string_view {
string *data;
size_t begin, len;
// ...
};
现在,我希望能够使用string_view
对象检查映射中是否存在键。不幸的是,std::unordered_map::find
接受Key
参数,而不是一般的T
参数。
(当然,我可以将一个“提升”为string
,但这会导致我想要避免的分配。)
我想要的是像这样的东西
template<class Key, class Value>
class unordered_map
{
template<class T> iterator find(const T &t);
};
这将需要适当地定义operator==(T, Key)
和std::hash<T>()
,并将迭代器返回到匹配值。
有什么变通方法吗?
发布于 2020-09-28 19:17:27
我也面临着同样的问题。
我们需要两个结构:
struct string_equal {
using is_transparent = std::true_type ;
bool operator()(std::string_view l, std::string_view r) const noexcept
{
return l == r;
}
};
struct string_hash {
using is_transparent = std::true_type ;
auto operator()(std::string_view str) const noexcept {
return std::hash<std::string_view>()(str);
}
};
对于unordered_map:
template <typename Value>
using string_unorderd_map = std::unordered_map<std::string, Value, string_hash, string_equal>;
对于unordered_set:
using string_unorderd_set = std::unordered_set<std::string, string_hash, string_equal>;
现在可以使用string_view了。
发布于 2016-01-05 07:50:52
这种解决方案有缺点,这可能会也可能不会使其在您的环境中可行。
您可以创建一个包装类:
struct str_wrapper {
const char* start, end;
};
并将您的地图更改为使用str_wrapper作为其键。您必须向str_wrapper添加2个构造函数,一个用于std::string,另一个用于您的string_view。主要的决定是让这些构造函数执行深度复制还是浅复制。
例如,如果只将std::string用于插入,而将str_view仅用于查找,则可以将std::string构造函数设为深层,而将str_view构造函数设为浅(如果在unordered_map周围使用自定义包装器,则可以在编译时强制执行)。如果您希望避免在深度副本上发生内存泄漏,则需要额外的字段来支持适当的销毁。
如果您的用法更加多样化(查找std::string或通过str_view插入),将会有一些缺点,这可能会使这种方法过于令人反感,以至于不可行。这取决于您的预期用途。
发布于 2020-04-01 15:12:45
我只介绍我在github上找到的一个变体,它涉及到定义一个包装std的新映射类。
重新定义一些密钥API来拦截我们想要的适配器,并使用静态字符串来复制密钥。
这不一定是一个好的解决方案,但有趣的是,对于那些认为它足够好的人来说,它的存在是很有趣的。
原件:
https://gist.github.com/facontidavide/95f20c28df8ec91729f9d8ab01e7d2df
代码要点:
template <typename Value>
class StringMap: public std::unordered_map<std::string, Value>
{
public:
typename std::unordered_map<string,Value>::iterator find(const nonstd::string_view& v )
{
tmp_.reserve( v.size() );
tmp_.assign( v.data(), v.size() );
return std::unordered_map<string, Value>::find(tmp_);
}
typename std::unordered_map<std::string,Value>::iterator find(const std::string& v )
{
return std::unordered_map<std::string, Value>::find(v);
}
typename std::unordered_map<std::string,Value>::iterator find(const char* v )
{
tmp_.assign(v);
return std::unordered_map<std::string, Value>::find(v);
}
private:
thread_local static std::string tmp_;
};
演职人员:
https://stackoverflow.com/questions/34596768
复制相似问题