使用可变参数模板的多键映射
Multikey map using variadic templates
我正在尝试使用 c++ 中的可变参数模板实现具有不同访问键的映射。我想要得到的是使这样的语法工作:
MultikeyMap<int, double, float> map1; // int and double are keys, float is value type
map1[ 2 ] = 3.5;
map1[ 5.7 ] = 22;
MultikeyMap<unsigned long long, int, float, double, int> map2; // more keys, int is value type
map2[100000000000ULL] = 56;
// etc...
我现在的样子:
template<class V, class... Krest>
class MultikeyMap;
template<class V, class K, class... Krest>
class MultikeyMap<V, K, Krest...> : protected std::map<K, V>,
protected MultikeyMap<V, Krest...>
{
public:
template<class T>
void insert( const T& t, const V& v )
{
std::map<T, V>::insert( make_pair( t, v ));
}
template<class T>
const V* find( const T& k )
{
typedef std::map<T,V> currentMap;
currentMap::const_iterator it = currentMap::find( k );
return it == currentMap::end() ? 0 : &it->second;
}
};
template<class V>
class MultikeyMap<V>
{};
我没有在插入和查找中返回迭代器以使代码变得简单。
我看到这个解决方案有两个主要缺陷。
首先,值类型在模板参数列表中排在第一位。最初我试图写
template<class K, class... Krest, class V>
class MultikeyMap<K, Krest..., V>
但是编译器坚持认为"如果类模板部分专用化的参数是包扩展,则应是最后一个参数"。
其次是来自 std::maps 的受保护继承。我真的很想使用合成而不是那个,但在这种情况下,我看不到访问存储地图的方法。如果有static_if,我会写
template<class V, class K, class... Krest>
class MultikeyMap<V, K, Krest...> : protected MultikeyMap<V, Krest...>
{
public:
template<class T>
void insert( const T& t, const V& v )
{
static if( is_same<T,K>::value )
m_map.insert( make_pair( t, v ));
else
MultikeyMap<V, Krest...>::insert( t, v );
}
private:
std::map<K,V> m_map;
};
请就我提到的问题提供建议。如果有更好的方法,我会很高兴学习。
感谢您的阅读。
更简单但不完全等价的方法可能是Boost.Bimap或Boost.MultiIndex。
前者是一个映射,键可以查找值,反之亦然,而后者则更通用:它是一个具有任意数量索引的容器,允许排序("类似列表"(、随机访问("类似矢量"(、关联("类似映射"(和散列访问。
您可以尝试将可变参数模板包装在 Boost.MultiIndex 周围,那么至少您不必重新实现所有插入/擦除逻辑(而只需精简包装器(。
注意:Boost.MultiIndex 不需要可变参数类型序列,您还可以使用成员函数的可变参数序列提取用户定义类的各种数据成员作为主数据类型。
我的做法:
template<class V, class K, class... Krest>
class MultikeyMap : MultikeyMap<V, Krest...>,
MultikeyMap<V, K>
{
using ParentMM = MultikeyMap<V, Krest...>;
using Parent = MultikeyMap<V, K>;
public:
using ParentMM::insert;
using Parent::insert;
using ParentMM::find;
using Parent::find;
using ParentMM::operator[];
using Parent::operator[];
};
template<class V, class K>
class MultikeyMap<V, K>
{
std::map<K, V> k_map;
public:
void insert(const K& k, const V& v)
{
k_map.insert(std::make_pair(k, v));
}
const V* find( const K& k ) const
{
auto it = k_map.find(k);
if (it != k_map.end())
return &it->second;
return nullptr;
}
V& operator[](const K& k)
{
return k_map[k];
}
};
继承在这里似乎是合适的,因为它结合了多个实现的行为。我将基地设为私有,因为无论哪种方式都需要using
声明才能使成员可见。只有基本事例具有作为成员的std::map
。
我不会费心反转模板参数,这与用于std::tuple
的技巧相同,只需查找您最喜欢的 STL 实现即可。
编辑
这是相同的代码,除了我提到的微不足道的更改,所以键在类型参数中排在第一位:
template<class Head, class... Tail>
struct Helper : Helper<Tail...> {
using Last = typename Helper<Tail...>::Last;
};
template<class T>
struct Helper<T> {
using Last = T;
};
template<class K, class... Rest>
class MultikeyMap : MultikeyMap<Rest...>,
MultikeyMap<K, typename Helper<Rest...>::Last>
{
using ParentMM = MultikeyMap<Rest...>;
using Parent = MultikeyMap<K, typename Helper<Rest...>::Last>;
public:
using ParentMM::insert;
using Parent::insert;
using ParentMM::find;
using Parent::find;
using ParentMM::operator[];
using Parent::operator[];
};
template<class K, class V>
class MultikeyMap<K, V>
{
std::map<K, V> k_map;
public:
void insert(const K& k, const V& v)
{
k_map.insert(std::make_pair(k, v));
}
const V* find( const K& k ) const
{
auto it = k_map.find(k);
if (it != k_map.end())
return &it->second;
return nullptr;
}
V& operator[](const K& k)
{
return k_map[k];
}
};
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- std::具有相同基类的类的变体
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 访问者访问变体并返回不同类型时出错
- 将函数类成员映射到类本身内部
- 如何在 C# 中映射双 C 结构指针?
- 如何在C++中使用结构生成映射
- 使用std::函数映射对象方法
- 如何加载(或映射)文件部分的最大大小,但适合在Windows上的RAM
- C++映射分割错误(核心转储)
- 内联映射初始化的动态atexit析构函数崩溃
- 使用"std::unordereded_map"映射到"std::list"对象
- 我应该使用什么来代替void作为变体中的替代类型之一
- 如何从多映射中删除特定的重复项
- 在未初始化映射的情况下,将值插入到映射的映射中
- C 如何在编译时检查变体映射的类型
- 模板功能以映射特定类型,并保留所有其他不变的
- (C++,提升::变体)提升变体映射的数据类型并对其执行数学运算
- 嵌入的多个变体类型映射
- 使用提升分配使用变量值初始化类似 JSON 的映射