基于对<iterator,iterator> </iterator,iterator>的范围

时间:2014-11-26 03:21:46

标签: c++ for-loop boost iterator

我对以下答案有疑问:

https://stackoverflow.com/a/15828866/2160256

如上所述,我们不能像BGL一样使用基于范围的:

   for(auto e : boost::edges(g))
       // do something with e

然而,here它指出,我们可以重载使用基于语义的范围所需的begin()和end()函数。所以我试过了:

   template<class I>
   I begin(std::pair<I,I>& p)
   { return p.first;}

   template<class I>
   I end(std::pair<I,I>& p)
   { return p.second;}

然而,编译器仍然抱怨:

  

错误:没有匹配的调用函数   “begin(std::pair<some_really_ugly_type,some_really_ugly_type>&)

我做错了什么?名称查找不起作用吗?或者这毕竟不可能吗? 我还发现了this answer,它有效,但是不应该使用开始/结束自由函数overlods吗? 此致,Marti

顺便说一句:我觉得写作真的很烦人

   typename Graph::edge_iterator ebegin, eend;
   std::tie(ebegin,eend) = boost::edges(_graph);
   std::for_each(ebegin,eend,[&](const edge_descriptor& e){/*do something with e*/;});

更新:C ++ 17现在应该允许以下内容: - )

auto [ebegin,eend] = boost::edges(_graph);

5 个答案:

答案 0 :(得分:6)

迭代器对范围的设计!该想法被语言和图书馆规范明确拒绝。参见例如

如果您“发现它很烦人”来编写tie()解决方法,请使用

for (auto& edge : make_iterator_range(boost::edges(_graph)))
    /*do something with edge*/;

您可以将boost::make_iterator_range替换为更短的内容,但是当我输入make_iterator_range时,我的编辑¹建议mir完成。这对我来说很快


¹当然,那个编辑是Vim

答案 1 :(得分:5)

在基于范围的for循环中,非成员begin()end()的名称查找仅使用ADL。它不执行普通的非限定查找。 §6.5.4[stmt.ranged] /p1.3:

  
      
  • 如果_RangeT是类类型,则会在类{{{{}}范围内查找 unqualified-id s beginend 1}}好像通过类成员访问   查找(3.4.5),如果其中任何一个(或两个)找到至少一个   声明,[...]

  •   
  • 否则, begin-expr end-expr _RangeT,   begin(__range)分别在end(__range)begin中查找。endbegin()   关联的命名空间(3.4.2)。 [注意:普通的非限定查询   (3.4.1)未执行。 - 结束记录]

  •   

因此,找不到您的end()和{{1}}重载。

答案 2 :(得分:1)

根据T.C.'s answer,您无法获得免费begin()end()个功能。但是,您可以做的只是创建自己的类,并向其添加成员beginend

template <typename I>
struct iter_pair : std::pair<I, I>
{ 
    using std::pair<I, I>::pair;

    I begin() { return this->first; }
    I end() { return this->second; }
};

只需使用它而不是正常的pair

std::vector<int> v = {1, 2, 3, 4, 5};

iter_pair<decltype(v.begin())> pr{v.begin(), v.end()};

for (int i : pr) {
    std::cout << i << ' ';
}
std::cout << std::endl;

答案 3 :(得分:1)

我会扩展Barry的答案并建议(直到C ++ 17)添加

template <typename I>
iter_pair<I> make_range(std::pair<I, I> p) {
    return iter_pair<I>(p);
}

用作

for (auto e : make_range(boost::edges(g)))
    // do something with e

答案 4 :(得分:0)

由于Boost FOREACH宏使用C ++ 03声明和显式模板代码,因此它应该使用传统的查找规则而不是特殊的for规则。

即使基于范围的for可用,您也可以确保它扩展旧方式。

另一种方法是创建自己的类,该类派生自该对,但包含beginend成员。然后写

for (e: mypair(p))

而不是

for (e: p)