简体   繁体   English

用于std :: set或std :: vector的C ++迭代器

[英]C++ Iterator for std::set or std::vector

Let's say I have this: 假设我有这个:

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

Now, during a refactor, I may have stuff in items or I may have it in sorted_items , but regardless I want to do the same thing with each item. 现在,在重构期间,我可能在items包含东西,或者可能在sorted_itemssorted_items ,但是无论我想对每个项目做同样的事情。 I want to do something like this: 我想做这样的事情:

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
}

When I go to compile this, I get errors complaining about incompatible operand types. 当我去编译它时,我会抱怨关于不兼容的操作数类型的错误。 Surely this is possible, no? 当然可以,不是吗?

You have two options: 您有两种选择:

  • use type-erasure to get a runtime polymorphism on the iterator ( any_range or any_iterator ) 使用类型擦除在迭代器( any_rangeany_iterator )上获取运行时多态性
  • delegate do_stuff to a function template that takes any kind of iterator do_stuff委托给采用任何迭代器的函数模板

Here is an illustration with code: 这是带有代码的插图:

#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;
}

The errors are correct: auto keyword works during compilation. 错误是正确的: auto关键字在编译期间有效。 In an easy way, it just deduces the type of assignment and uses this real type. 以一种简单的方式,它只是推导分配的类型并使用这种类型。 But decision if it's vector's iterator or set's is made in runtime. 但是决定是向量的迭代器还是集合的迭代器是在运行时决定的。 So type can not be deduced. 因此无法推论类型。 As SergeyA said, I'm wrong here, compiler fail on ?: operator, before auto. 正如SergeyA所说,我在这里错了,编译器在?:运算符上失败,然后自动。 But the reason is still the same - it has no idea which type to use for the result. 但是原因仍然是相同的-它不知道要使用哪种类型的结果。

You should probably use some more generic iterator type + polymorphism, or you can make this function parameterized on type , where T is an iterator type. 您可能应该使用一些更通用的迭代器类型+多态性,或者可以将此函数参数化为type,其中T是迭代器类型。 I would prefer to do it this way: 我更喜欢这样:

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);
}     

PS: It's a conception, I didn't test the code. PS:这是一个概念,我没有测试代码。

Both sides of the ternary operator need to have the same type. 三元运算符的两端都必须具有相同的类型。 In your case, they are different - std::vector<>::iterator and std::set<> iterator. 在您的情况下,它们是不同的-std :: vector <> :: iterator和std :: set <>迭代器。 A suitable solution seems to be some sort of a an iterator wrapper, which returns one or another depending on the initial condition. 合适的解决方案似乎是某种迭代器包装器,它会根据初始条件返回一个或另一个。

auto means the compiler will deduce the type of what follows, at compilation time. auto表示编译器将在编译时推断出后续类型。

The return type of the ternary conditional operator in this case is what follows the question mark, so it is std::set<StuffItem, StuffItemComparator>::iterator and the compiler tries to cast what follows the column ( std::vector<StuffItem>::iterator ) to this incompatible type, hence the compiler error. 在这种情况下,三元条件运算符的返回类型是问号std::set<StuffItem, StuffItemComparator>::iterator因此它是std::set<StuffItem, StuffItemComparator>::iterator ,并且编译器将尝试std::vector<StuffItem>::iteratorstd::vector<StuffItem>::iteratorstd::vector<StuffItem>::iterator )转换为此不兼容的类型,从而导致编译器错误。

What you can do is make your item processing code generic, like so: 您可以做的是使商品处理代码通用,如下所示:

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 );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM