0

在第 3 章草稿的第 82 页:C++ 之旅:抽象机制作者写道:

如果我们还想对Vector使用 range-for 循环,我们必须定义合适的begin()end()函数:

template<typename T>
T∗ begin(Vector<T>& x)
{
    return &x[0]; // pointer to first element
}

template<typename T>
T∗ end(Vector<T>& x)
{
    return x.begin()+x.size(); // pointer to one-past-last element
}

鉴于这些,我们可以写:

void f2(const Vector<string>& vs) // Vector of some strings
{
    for (auto s : vs)
        cout << s << ’\n’;
}

请注意,类模板Vector在草案的第 81 页中定义。

4

3 回答 3

5

为了使基于范围的 for 工作,编译器需要找到一个合适的函数来获取迭代器。

这就是基于范围的 C 数组工作的原因。显然,数组不能有成员函数,所以标准库提供了两个类似定义的函数:

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

同样对于end.

从标题中回答您的问题:它们可以,但这不是必需的。您可以在与您的类相同的命名空间中定义自由函数,它们会被找到。

于 2013-08-01T12:52:20.757 回答
4

如果它不是数组或容器,.begin()它将.end()通过Argumentdependent name查找。

这里说:

请记住有关基于范围的以下事实:

  • 自动识别数组。

  • 识别具有 .begin() 和 .end() 的容器。

  • 对其他任何内容使用依赖于参数的查找 begin() 和 end()。

于 2013-08-01T12:52:12.047 回答
2

在这样的范围内:

for ( for-range-declaration : expression ) statement

该标准规定,如果表达式是类类型,编译器会查找成员( (expression).begin(), (expression).end())或自由函数(begin((expression)), )。end((expression))

因此,您可以提供成员函数或自由函数(需要在依赖于参数的查找范围内)。

C++11,第 6.5.4 节 [stmt.ranged]

这是基于范围的 for 根据标准所做的:

for ( for-range-declaration : expression ) statement

range-init = ( expression )

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

begin-exprend-expr描述为:

  • if_RangeT是数组类型,begin-exprend-expr_ range_range + _ bound分别在哪里_bound是数组绑定。如果_RangeT是一个未知大小的数组或一个不完整类型的数组,则程序是非良构的;

  • 如果_RangeT是类类型,则在类 _RangeT 的范围内查找非限定 ID 的开始和结束,就像通过类成员访问查找 (3.4.5) 一样,并且如果其中一个(或两者)找到至少一个声明,则 beginexpr 和end-expr 分别是 __range.begin() 和 __range.end();

  • 否则,begin-exprend-expr分别是begin(__range)end(__range),其中beginend使用参数相关查找 (3.4.2) 进行查找。出于此名称查找的目的,命名空间 std 是一个关联的命名空间。

于 2013-08-01T12:58:56.490 回答