是否可以使函数的返回类型取决于类的模板中类型的某些条件?
我有一个自定义哈希映射,名为 MyHashMap 。
它有一个正确的begin()和end()函数,它返回迭代器。
template <class K, class T> class MyHashMap{
MyIterator<K,T> begin() { ..... }
MyIterator<K,T> end() { ...... }
//.... some function ....
}
迭代器有一个简洁的运算符*(),运算符++()等
template <class K, class T> class MyIterator{
std::pair<K,T> operator*(){ ..... }
//.... some function ....
}
现在我可以使用 MyHashMap 代替 std :: unordered_map ,非常好。
我是否可以扩展此类以替换 std :: hashset ?怎么样?
具体来说,我想直接用此类替换 std :: hashset 和 std :: unordered_map 。
两种数据结构(map&amp; hashset)似乎非常相似(代码和逻辑),将它们放在一个地方可以提高可维护性。
问题是有几百次调用Hash设置如下: -
std::hashset<X> hashset; //old code, will be deleted
MyHashMap<X, MyHashMap_DUMMY > hashset; // new code
for(auto x: hashset ){
x.doSomething(); //# old code, compile error, but I don't want to change this
}
我无法更改哈希映射的返回签名,因为有些代码将其用作实际地图,而不是设置: -
for(auto xy: hashmap ){ //HashMap<X,Y>
x.first.doSomething(); //# I don't want to change this line too
}
注意:不应更改某些行(#)。原因是: -
他们出现在很多地方。
更改它们也会使代码变脏。
将来我可能想将 MyHashMap / MyHashSet 替换回 std :: unordered_map / std :: hashset 以后。
如果我不修改#-line,几乎没有什么工作可以改变(高模块性和可维护性)。
创建 MyHashSet 以封装 HashMap 。它的缺点是我将有另一层抽象,有两个类,更多的错误和更少的可维护性。
我希望有一个技巧可以利用/操纵模板来检测T是MyHashMap_DUMMY。
换句话说,
允许使用C ++ 11和C ++ 14.
答案 0 :(得分:1)
您可以使用tag dispatching在编译时启用T
:
template <class K, class T> struct MyIterator
{
decltype(auto) operator*()
{
return indirection_hlp(std::is_same<T, MyHashMap_DUMMY>{});
}
std::pair<K, T>& indirection_hlp(std::false_type)
{
// ...
}
K& indirection_hlp(std::true_type)
{
// ...
}
// other stuff
};
如上所述,这需要C ++ 14(因为decltype(auto) operator*()
),但是同样的事情可以在C ++ 11中实现,只需要输入更多内容。
我不确定在效率甚至可靠性方面重用MyHashMap
是否是一个好主意(你可能需要在几个地方进行这种调度),但如果它真的是你需要的话,这是一个相当干净的解决方案,它本身不会引入任何运行时开销。
请注意,map / set键在标准库中实际上是const
,因此间接运算符的返回类型应该是std::pair<const K, T>&
和const K&
。
另请注意,for循环使用auto x
,这将推断出非引用类型,因此会制作副本,这可能是您想要的一个集合,但可能不适用于地图(它将复制std::pair
)。
对于C ++ 11,它看起来像这样:
template <class K, class T> struct MyIterator
{
std::pair<K, T>& indirection_hlp(std::false_type)
{
// ...
}
K& indirection_hlp(std::true_type)
{
// ...
}
auto operator*() -> decltype(indirection_hlp(std::is_same<T, MyHashMap_DUMMY>{}))
{
return indirection_hlp(std::is_same<T, MyHashMap_DUMMY>{});
}
// other stuff
};
注意indirection_hlp
在这种情况下需要在operator*
之前声明,因为它出现在函数体之外,在名称查找只找到先前声明的地方(它没有查看)全班定义)。