C ++ 11设置范围基于使用结构作为元素

时间:2016-11-22 18:41:03

标签: c++11 set range

假设我有一个这样的结构:

ORDER BY

还有一套Something类型:

struct Something{
    string name;
    int code;
};

这有什么问题?

set<Something> myset;
myset.insert({"aaa",123,});
myset.insert({"bbb",321});
myset.insert({"ccc",213});

沿着相同的路线...为什么我不能使用这样的东西修改元素(即使集合包含普通的int项目)?

for (auto sth : myset){
       cout << sth.name;
       cout << sth.code;
}

我知道我可以用矢量和地图做到这一点。为什么不设置?

谢谢!

1 个答案:

答案 0 :(得分:1)

修改集合的元素意味着它在集合中的位置可以改变。因为您的编译器无法确定特定集合用于确定其元素的顺序的确切内容。嗯,从理论上讲,它可以,但即使这样,在迭代容器时也几乎不可能跟踪重新排列。这没有任何意义。

你可以做什么,如果你想以一种你知道不会改变它们在一个集合中的顺序的方式来修改集合的元素,你可以使你的结构的非排序成员变得可变。请注意,如果您犯了错误并且设置的顺序受到干扰,则该设置上的任何其他操作(如二进制搜索)将在错误修改后给出错误的结果。如果你不想让成员变成可变的话,const_cast是一个选项,同样需要注意。

详细说明我的答案,例如:

#include <iostream>
#include <set>

struct bla
{
  std::string name;
  int index;
};

bool operator<(const bla& left, const bla& right) { return left.index < right.index; }

int main()
{
  std::set<bla> example{{"har", 1}, {"diehar", 2}};

  // perfectly fine
  for(auto b : example)
    std::cout << b.index << ' ' << b.name << '\n';

  // perfectly fine - name doesn't influence set order
  for(auto& b : example) // decltype(b) == const bla&
    const_cast<std::string&>(b.name) = "something";

  // better than first loop: no temporary copies
  for(const auto& b : example)
    std::cout << b.index << ' ' << b.name << '\n';

  // using a "universal reference auto&&", mostly useful in template contexts
  for(auto&& b : example) // decltype(b) == const bla&
    std::cout << b.index << ' ' << b.name << '\n';

  // destroying order of the set here:
  for(auto& b : example)
    const_cast<int&>(b.index) = -b.index;

  // anything here relying on an ordered collection will fail
  // This includes std::set::find, all the algorithms that depend on uniqueness and/or ordering

  // This is pretty much all that will still work, although it may not even be guaranteed
  for(auto&& b : example)
    std::cout << b.index << ' ' << b.name << '\n';
}

Live code on Coliru

请注意,第一个const_cast只是正常,因为基础example首先不是const