C++中的"for each"循环如何知道数组的长度

Bre*_*ren 5 c++ arrays foreach for-loop

我在http://www.cplusplus.com/doc/tutorial/arrays/上查看以下示例,我无法弄清楚第二个for循环是如何工作的.for循环如何知道数组何时结束.如果它能弄明白为什么第一个循环不使用类似的方法?我的印象是无法确定阵列的长度.我不确定如何调和这些观念.谢谢!

编辑:感谢所有的好答案!

#include <iostream>
using namespace std;
int main()
{
  int myarray[3] = {10,20,30};

  for (int i=0; i<3; ++i)
    ++myarray[i];

  for (int elem : myarray)
    cout << elem << '\n';
}
Run Code Online (Sandbox Code Playgroud)

Jer*_*fin 5

这个工作的原因是for有效的循环1使用std::beginstd::end.反过来,这些工作,因为它们专门为内置数组提供重载,如下所示:

template <class T, size_t N>
T *begin(T (&array)[N]) {
    return array;
}

template <class T, size_t N>
T *end(T (&array)[N]) {
    return array+N;
}
Run Code Online (Sandbox Code Playgroud)

虽然它(显然)在原始(1998)C++标准发布之前尚未实现,但该技术不需要除C++ 98中提供的任何语言功能之外的任何语言功能.C++ 11编写了这项技术并将其付诸实践.

因为在这种情况下,参数被指定为对数组的引用,所以只有当参数确实是一个数组时,类型推导才会成功.在这种情况下std::begin,还有一些版本支持其他参数类型并使用(例如)集合begin()end()成员,如果匹配该类型.


1."有效",在这种情况下,这意味着有一些情况,其中范围为基础的循环使用beginend,和其他人在他们没有.如果你是技术人员,他们不是用于数组,但直接完成类似的计算.同样,对于具有beginend成员的容器类型,直接使用它们.如果这两个时间都不是真的,那么begin(range)end(range)被使用,这可以使用std::begin/ std::endbegin(x)/ end(x)由参数依赖查找发现对.


Ben*_*igt 3

您有一个误解,认为 range-for 需要提前知道迭代次数(“长度”)。它不是。

它确实需要一个终止条件,其形式为it != __endwhere__end = x.end()__end = end(x)

当然,数组不能改变它们的大小,因此在这种情况下,检测结束和知道长度是等效的(长度可以通过开始、结束和指针减法获得)。

正如 Oli 在评论中提到的,数组的类型确实包含长度信息,并std::end使用数组引用作为其参数,以避免指针衰减而丢失此信息。

定义基本上是:

namespace std
{
    template<typename T, size_t N> 
    T* end(T (&array)[N])
    {
        return array + N;
        // or if you want to be cute
        // return 1[&array];
    }
}
Run Code Online (Sandbox Code Playgroud)

当数组引用中的绑定是非类型模板参数时,它是可推导的。在编写接受数组的函数时,可以利用这一点。

(编译器实际上array + N内置了数组末尾的计算,但它并不用于std::end()此目的。但是无论如何内联后都没有区别,了解如何发挥编译器所做的相同技巧是很有用的。 )