简体   繁体   English

基于对的范围<Iterator,Iterator>

[英]Range based for with pair<Iterator,Iterator>

I have a question with respect to the following answer: 我对以下答案有疑问:

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

As stated there, we cannot use range based for with BGL like this: 如上所述,我们不能像BGL这样使用基于范围的BGL:

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

However, here it states, that we can overload the begin() and end() functions that are required to use range based for semantics. 但是, 这里指出,我们可以重载使用基于语义的范围所需的begin()和end()函数。 So I tried: 所以我尝试过:

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

However, the compiler still complains: 但是,编译器仍抱怨:

error: no matching function for call to ' begin(std::pair<some_really_ugly_type,some_really_ugly_type>&) ' 错误:没有用于调用' begin(std::pair<some_really_ugly_type,some_really_ugly_type>&)的匹配函数

What am I doing wrong? 我究竟做错了什么? Does the name lookup not work? 名称查找不起作用吗? Or is this not possible after all? 或者这毕竟不可能吗? I also found this answer , which works, but shouldtn't it be possible with the begin/end free function overlods as well? 我也找到了这个答案这个答案是有效的,但是开头/结尾自由函数的过度也不应该是可能的吗? Regards, Marti 问候,马蒂

BTW: I find it really tiresome to write 顺便说一句:我觉得写作真的很烦人

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

UPDATE: C++17 should now allow the following :-) 更新:C ++ 17现在应该允许以下内容:-)

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

Iterator pairs are not ranges by design! 迭代器对不是设计范围! The idea was specifically rejected from the language and library specification. 该想法被语言和图书馆规范明确拒绝。 See eg 见例如

If you "find it tiresome" to write the tie() workaround, just use 如果您“发现它很烦人”来编写tie()解决方法,请使用

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

You could alias boost::make_iterator_range something shorter, but my editor¹ suggests make_iterator_range as completion when I type mir . 你可以将boost::make_iterator_range别名更短,但是当我输入mir时,我的编辑器¹建议make_iterator_range为完成。 This is plenty speedy for me 这对我来说很快


¹ of course, that editor is Vim ¹当然,那个编辑是Vim

In a range-based for loop, name lookup for non-member begin() and end() uses ADL only. 在基于范围的for循环中,非成员begin()end()名称查找仅使用ADL。 It doesn't perform ordinary unqualified lookup. 它不执行普通的非限定查找。 §6.5.4 [stmt.ranged]/p1.3: §6.5.4[stmt.ranged] /p1.3:

  • if _RangeT is a class type, the unqualified-id s begin and end are looked up in the scope of class _RangeT as if by class member access lookup (3.4.5), and if either (or both) finds at least one declaration, [...] 如果_RangeT是一个类类型,则在类_RangeT的范围内查找unqualified-id s beginend ,就像通过类成员访问查找(3.4.5)一样,并且如果其中任何一个(或两者)找到至少一个声明, [...]

  • otherwise, begin-expr and end-expr are begin(__range) and end(__range) , respectively, where begin and end are looked up in the associated namespaces (3.4.2). 否则, begin-exprend-expr分别是begin(__range)end(__range) ,其中beginend在相关的命名空间中查找(3.4.2)。 [ Note : Ordinary unqualified lookup (3.4.1) is not performed. [ 注意 :不执行普通的非限定查找(3.4.1)。 end note ] - 结束说明 ]

Hence, your begin() and end() overloads are not found. 因此,找不到您的begin()end()重载。

You cannot have free begin() and end() functions as per TC's answer . 根据TC的回答,您不能拥有免费的begin()end()函数。 However, what you can do, is just make your own class and add member begin and end to it: 但是,您可以做的只是创建自己的类并添加成员的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; }
};

And just use that instead of a normal pair : 而只是使用它而不是正常的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;

I would expand on Barry's answer and suggest (until C++17) to add 我将扩展Barry的答案并建议(直到C ++ 17)添加

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

to be used as 用作

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

Since the Boost FOREACH macro uses C++03 declarations and explicit template code, it ought to work with conventional lookup rules instead of special for rules. 由于Boost FOREACH宏使用C ++ 03声明和显式模板代码,因此它应该使用传统的查找规则而不是特殊for规则。

You might make sure that it expands the old way even though range-based for is available. 其膨胀,即使范围为基础的旧的方式也可以确保for可用。

Another approach would be to make your own class that is derived from the pair, but contains the begin and end members. 另一种方法是创建自己的类,该类派生自该对,但包含beginend成员。 Then write 然后写

for (e: mypair(p))

Instead of 代替

for (e: p)

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

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