std::set或std::vector的迭代器

C++ Iterator for std::set or std::vector

本文关键字:std 迭代器 set vector      更新时间:2023-10-16

我们设这个:

struct HoldStuff {
  std::vector<StuffItem> items;
  std::set<StuffItem, StuffItemComparator> sorted_items;
}

现在,在重构过程中,我可能在items中有东西,也可能在sorted_items中有东西,但无论如何,我都想对每个项目做同样的事情。我想这样做:

HoldStuff holder;  // assume it was filled earlier
auto iter = holder.items.empty() ? holder.sorted_items.begin() :
                                   holder.items.begin();
auto iter_end = holder.items.empty() ? holder.sorted_items.end() :
                                       holder.items.end();
for (; iter != iter_end; ++iter) {
    auto& item = *iter;
    // Do stuff
}

当我去编译这个时,我得到错误抱怨不兼容的操作数类型。这当然是可能的,不是吗?

您有两个选择:

  • 使用类型擦除在迭代器(any_rangeany_iterator)上获得运行时多态性
  • do_stuff委托给接受任意类型迭代器的函数模板

下面是一个带有代码的插图:

#include <vector>
#include <set>
#include <iostream>
#include <boost/range/any_range.hpp>
template<typename Iterator>
void do_stuff(Iterator begin, Iterator end) {}
int main()
{
  std::vector<int> items;
  std::set<int> sorted_items;
  // first option
  typedef boost::any_range<int, boost::forward_traversal_tag, int&, std::ptrdiff_t> my_any_range;
  my_any_range r;
  if(items.empty())
    r = my_any_range(sorted_items);
  else
    r = my_any_range(items);
  for (auto& x : r) {
    std::cout << x << " ";
  }
  // second option
  // this could also be a lambda and std::for_each
  if(items.empty())
    do_stuff(sorted_items.begin(), sorted_items.end());
  else
    do_stuff(items.begin(), items.end());
  return 0;
}

三元操作符的两边必须具有相同的类型。在您的例子中,它们是不同的——std::vector<>::iterator和std::set<> iterator。一个合适的解决方案似乎是某种迭代器包装器,根据初始条件返回一个或另一个。

错误是正确的:auto关键字在编译过程中工作。简单地说,它只是推导出赋值的类型,并使用这个类型。但是决定它是vector的迭代器还是set的迭代器是在运行时做出的。所以类型不能被推断出来。正如SergeyA所说,我在这里错了,编译器在?:操作符上失败,在auto之前。但是原因还是一样的——它不知道使用哪种类型作为结果。

您可能应该使用一些更泛型的迭代器类型+多态性,或者您可以根据类型将该函数参数化,其中T是一个迭代器类型。我更喜欢这样做:

template<class T> do_stuff(T &c) {  for (auto &el : c) { /*Whatever*/ } }
...
if (!items.empty()) {
    do_stuff(items);
} else if (!sorted_items.empty()) {
    do_stuff(sorted_items);
}     

注::这是一个概念,我没有测试代码

auto表示编译器将在编译时推断出后面内容的类型。

在这种情况下,三元条件运算符的返回类型是问号后面的类型,所以它是std::set<StuffItem, StuffItemComparator>::iterator,编译器试图将列(std::vector<StuffItem>::iterator)后面的类型强制转换为这种不兼容的类型,因此编译器错误。

你能做的是使你的项目处理代码通用,像这样:

auto doStuff = [] (StuffItem& item) {
  // do stuff with item...
};
if( holder.items.size() )
  for_each( holder.items.begin(), holder.items.end(), doStuff );
else if( holder.sorted_items.size() )
  for_each( holder.sorted_items.begin(), holder.sorted_items.end(), doStuff );