迭代非const std :: unordered_set

时间:2017-06-23 14:58:19

标签: c++11 iterator const unordered-map unordered-set

我有std::unordered_set,其中包含类bar的实例。

我希望迭代集合中的所有bar,并在每个void foo(bar& b)上调用一些foo函数。

您可能会从功能签名中注意到我希望bar& b以某种方式更改foo参数的状态。

现在,我知道bar以一种影响哈希或平等比较的方式不会改变const bar&,但我仍然有问题。

然而,我迭代了这个集合,我所希望的最好的是const_cast显然不会起作用。

我可以想到几种可能的方法:

  1. 使用std::unordered_map。不知道这是否会起作用(还)。这对我来说有点难闻,但我很高兴能够开悟!!
  2. 使用std::unordered_set代替const,即使我只能获得密钥的bar,我也可以使用该密钥查找foo对象并安全地呼叫 let mat = SCNMatrix4FromMat4(currentFrame.camera.transform) let dir = SCNVector3(-1 * mat.m31, -1 * mat.m32, -1 * mat.m33) let currentPosition = pointOfView.position + (dir * 0.1) if button!.isHighlighted { if let previousPoint = previousPoint { let line = lineFrom(vector: previousPoint, toVector: currentPosition) let lineNode = SCNNode(geometry: line) lineNode.geometry?.firstMaterial?.diffuse.contents = lineColor sceneView.scene.rootNode.addChildNode(lineNode) } }
  3. 我真的很感激一些建议!

    提前致谢!

2 个答案:

答案 0 :(得分:1)

this answer已经显示了一些干净的解决方案。

另一种干净的方法是通过指针添加一个间接层。即使指针本身是const,指向的数据也不会是:

struct Bar
{
    int key;
    std::unique_ptr<int> pValue;
};

std::unordered_set< Bar, BarHash, BarEqual > bars;

for( const auto& bar : bars )
{
    // Works because only the pointer is constant, not the data pointed to.
    *bar.pValue = 42;
}   

这显然有额外内存分配的开销,存储指针所需的空间以及通过指针访问值时的间接。

如果要保留值语义,您还必须编写自定义复制构造函数和赋值运算符。

答案 1 :(得分:0)

  

使用const_cast。不知道这是否会起作用(还)。这对我来说有点难闻,但我很高兴能够开悟!!

是的,它会起作用。您可以轻松地重载foo(bar const&)const_cast引用,然后调用foo(bar&)。我同意你的看法,它闻起来很糟糕,并指出设计存在缺陷。您可能需要重新审视设计,看看是否有一个干净的解决方案。

  

使用std::unordered_map代替std::unordered_set,这样即使我只能获得密钥的const,我也可以使用该密钥查找bar对象并安全地调用foo < / p>

这与第一种方法没有什么不同。 std::unordered_set<T>基本上是std::unordered_map<T, bool>

潜在的清洁解决方案:

  1. 从集合中获取对象的副本,从集合中删除条目,更新副本,然后将副本放回集合中。如果证明太贵了......

  2. 使用std::vector<Bar>。你可以从矢量中得到一个Bar&,一切都很好。

  3. 将不会影响其哈希值的Bar成员变量设为mutable。然后,您可以使用foo(Bar const&)并使用对集合中对象的引用直接调用它。