c++11中基于范围的for

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9005835/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 12:12:03  来源:igfitidea点击:

range-based for in c++11

c++gccfor-loopc++11

提问by Farzam

in c++ 11 if we have a set<int> S; we could say:

在 C++ 11 中,如果我们有一个set<int> S; 我们可以说:

for (auto i: S)
    cout << i << endl;

but can we force ito be a iterator, I mean write a code that is equivalent to:

但是我们可以强制i成为迭代器吗,我的意思是写一段代码,相当于:

for (auto i = S.begin(); i != S.end(); i++)
    cout << (i != s.begin()) ? " " : "" << *i;

or could we do something that we can understand the index of iin the set(or vector)?

或者我们可以做一些我们可以理解i集合(或向量)中的索引的事情吗?

and another question is how could we say that don't do this for all elements in Sbut for first half of them or all of them except the first one.

另一个问题是我们怎么能说不对中的所有元素执行此操作,S而是对其中的前半部分或除第一个之外的所有元素执行此操作。

or when we have a vector<int> V, and want to print its first nvalues what should we do? I know we can create a new vector but it takes time to copy a vector to a new vector.

或者当我们有一个vector<int> V, 并且想要打印它的第一个n值时我们应该怎么做?我知道我们可以创建一个新的向量,但是将一个向量复制到一个新的向量需要时间。

回答by Damon

No, unluckily. See what the standard says:

不,很不幸。看看标准怎么说:

The range-based for statement for ( for-range-declaration : expression ) statement is equivalent to

{
    auto && __range = ( expression );
    for ( auto __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin ) {
        for-range-declaration = *__begin;
        statement
    }
}

where __range, __begin, and __end are variables defined for exposition only

for ( for-range-declaration : expression ) 语句的基于范围的 for 语句等效于

{
    auto && __range = ( expression );
    for ( auto __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin ) {
        for-range-declaration = *__begin;
        statement
    }
}

其中 __range、__begin 和 __end 是仅为说明而定义的变量

In other words, it already iterates from beginto endand already dereferences the iterator, which you never get to see.

换句话说,它已经从beginto开始迭代end并且已经取消引用迭代器,这是你永远看不到的。

回答by Matthieu M.

The principle of the range-based foris to iterate over the whole range.

基于范围的原则for是迭代整个范围。

However youdecide what the range is, therefore you can operate on the range itself.

但是,决定范围是什么,因此您可以对范围本身进行操作。

template <typename It>
class RangeView {
public:
  typedef It iterator;

  RangeView(): _begin(), _end() {}
  RangeView(iterator begin, iterator end): _begin(begin), _end(end) {}

  iterator begin() const { return _begin; }
  iterator end() const { return _end; }

private:
  iterator _begin;
  iterator _end;
};

template <typename C>
RangeView<typename C::iterator> rangeView(C& c, size_t begin, size_t end) {
  return RangeView<typename C::iterator>(
           std::next(c.begin(), begin),
           std::next(c.begin(), end)
         );
}

template <typename C>
RangeView<typename C::const_iterator> rangeView(C const& c, size_t begin, size_t end) {
  return RangeView<typename C::const_iterator>(
           std::next(c.begin(), begin),
           std::next(c.begin(), end)
         );
}

Okay, this seriously ressemble Boost.Range...

好吧,这真的很像 Boost.Range...

And now, let's use it!

现在,让我们使用它!

for (auto i: rangeView(set, 1, 10)) {
  // iterate through the second to the ninth element
}

回答by Armen Tsirunyan

No, you can't.

不,你不能。

for (... : ...)

is called forinstead of foreachonly for the reason of not introducing a new keyword. The whole point of foreachis a quick short syntax for iterating all elements without caring for their index. For all other situations there's simple forwhich serves its purpose quite effectively.

被调用for而不是foreach仅仅因为不引入新关键字的原因。重点foreach是迭代所有元素而不关心它们的索引的快速简短语法。对于所有其他情况,simplefor可以非常有效地实现其目的。

回答by Drew Dormann

You can'tin a set. Use the traditional forsyntax or maintain your own index counter.

你不能在一个set. 使用传统for语法或维护自己的索引计数器。

You canin a vectoror other container with a flat layout like std::arrayor a C-style array. Change it to use a reference.:

您可以在一个vector或其他具有平面布局的容器中,如std::array或 C 样式数组。将其更改为使用引用。

for (auto &i: S)

Then you can compare the address of iwith the address of s[0]to get the index.

然后您可以将 的地址i与 的地址进行比较s[0]以获取索引。

回答by Seth Carnegie

For the general case, you'd have to use a seperate variable:

对于一般情况,您必须使用单独的变量:

int i = 0;

for (auto x : s)
    cout << (i++ ? " " : "") << x << endl;

There are, of course, tricks for certain containers like vector, but none work for every container.

当然,对于某些容器(例如 )vector,有一些技巧,但没有一个适用于每个容器。

You would probably be better off using the plain forloop for this purpose.

为此,您最好使用普通for循环。

回答by Dietmar Kühl

Range-based foris intended for simple cases. I'd expect to to mildly useful while protoyping something but would expect uses of it mostly gone long before things actually become a product. It may possibly useful to make life for beginners easier, but this is an area I can't judge (but what seems to drive a lot of the recent C++ discussions).

基于范围的for适用于简单的情况。我希望在对某些东西进行原型设计时会有一些用处,但希望它的用途在事物真正成为产品之前很久就已经消失了。让初学者的生活更轻松可能很有用,但这是一个我无法判断的领域(但似乎推动了最近的 C++ 讨论)。

The only somewhat constructive approach could be to use an adapter which references the underlying range and whose begin()and end()methods adjust the iterator appropriately. Also note that you probably want to hoist any special handling of the first or last element out of the loop processing the bulk of the data. Sure, it is only another check followed by a correctly predicted branch vs. no check and less pollution of the branch prediction tables.

唯一有点建设性的方法可能是使用引用基础范围的适配器,其begin()end()方法适当地调整迭代器。另请注意,您可能希望将第一个或最后一个元素的任何特殊处理提升到处理大量数据的循环之外。当然,这只是另一次检查,然后是正确预测的分支,而没有检查和更少的分支预测表污染。