如何遍历特定范围的 std::set/std::multiset?

How to iterate over a specific range of std::set/std::multiset?

std::set 喜欢 std::set<std::string> set={ "aaa", "bbb", "ccc", "ddd", "eee", "fff" }; 如何在不跟踪额外索引的情况下迭代此集合的特定范围 [a, b]?

像这样:

for(auto it = set.begin(); it!=set.begin()+b; ++it)
   std::cout << *it << " ";

或者像这样:

for(auto it = set.begin()+a; it!=set.begin()+b; ++it)
   std::cout << *it << " ";

其中 a<=bb<=set.size()

你不能做到 set.begin()+a,但你可以做到 std::advance(it, a):

#include <iostream>
#include <set>
#include <string>
 
int main()
{
    std::set<std::string> set={ "aaa", "bbb", "ccc", "ddd", "eee", "fff" };
    size_t a = 1, b = 4;
    auto it = set.begin(), it_end = set.begin();
    std::advance(it, a);
    std::advance(it_end, b);
    for(; it!= it_end; ++it)
        std::cout << *it << " ";
}

不幸的是,您不能执行 auto it = std::advance(set.begin(), a); 之类的操作,因为 advance 通过引用获取迭代器并就地更改它。

https://ideone.com/8nRjgr

更好的解决方案使用 std::next,感谢@Evg:

#include <iostream>
#include <set>
#include <string>
 
int main()
{
    std::set<std::string> set={ "aaa", "bbb", "ccc", "ddd", "eee", "fff" };
    size_t a = 1, b = 4;
    for(auto it = std::next(set.begin(), a), it_end = std::next(it, b-a); it != it_end; ++it)
        std::cout << *it << " ";
}

https://ideone.com/6wgpMZ

您可以编写自己的 slice class,有点像 std::span:

#include <cstdio>
#include <set>
#include <string>

template <class Iter>
class slice {
 private:
  Iter _beg;
  Iter _end;

 public:
  slice(Iter beg, Iter end) noexcept 
    : _beg{beg}
    , _end{end} 
  {}

  slice(Iter beg, std::size_t sz) noexcept 
    : slice(beg, std::next(beg, sz)) 
  {}

  auto begin() const noexcept { return _beg; }
  auto end() const noexcept { return _end; }
};

int main() {
  std::set<std::string> const set{"aaa", "bbb", "ccc", "ddd", "eee", "fff"};

  slice const sl(set.begin(), 3);

  for (auto const& elm : sl) std::puts(elm.c_str());
}

Godbolt