In page 82 of the draft of Chapter 3 : A Tour of C++: Abstraction Mechanisms写道:
如果我们还想为我们的 Vector 使用range-for循环,我们必须这样做 定义合适的开始()和结束()功能:
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’;
}
请注意,草稿的第81页中定义了类模板 Vector 。
答案 0 :(得分:5)
对于基于范围的工作,编译器需要找到一个合适的函数来获取迭代器。
如果使用的类型是一个类,它将首先在该类的范围内查找成员函数begin
和end
。
如果类型不是类或没有此类成员函数,则按Argument Dependent Lookup.
这是基于范围的原因,适用于C阵列。显然,数组不能有成员函数,因此标准库提供了两个与此类似的函数:
template<typename T, size_t N>
T* begin( T(&array)[N] )
{
return array;
}
,同样适用于end
。
要从标题中回答你的问题:他们可以,但这不是必要的。您可以在与您的类相同的命名空间中定义自由函数,它们将被找到。
答案 1 :(得分:4)
如果它不是包含.begin()
和.end()
的数组或容器,则会按Argument dependent name查找。
据说here:
请记住以下有关基于范围的事实:
自动识别数组。
识别具有.begin()和.end()的容器。
使用依赖于参数的查找begin()和end()用于其他任何内容。
答案 2 :(得分:2)
在以下范围内:
for ( for-range-declaration : expression ) statement
标准表示如果表达式是类类型,编译器会查找成员((expression).begin()
,(expression).end()
)或自由函数(begin((expression))
,end((expression))
)。 / p>
因此你可以提供成员函数或自由函数(需要在参数依赖查找的范围内)。
C ++ 11,§6.5.4[stmt.ranged]
根据标准,这是基于范围的:
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-expr
和end-expr
被描述为:
如果
_RangeT
是数组类型, begin-expr 和 end-expr 是 _ 范围 和 _range + _ 绑定 ,其中 _bound 是数组绑定的。如果 _RangeT 是未知大小的数组或不完整类型的数组,则该程序格式错误;如果
_RangeT
是类类型,则在类_RangeT的范围内查找unqualified-ids的开始和结束,就像通过类成员访问查找一样(3.4。 5),如果其中任何一个(或两个)找到至少一个声明,beginexpr和end-expr分别是__range.begin()和__range.end();否则, begin-expr 和 end-expr
begin(__range)
和 {{1} ,分别使用参数依赖查找(3.4.2)查找end(__range)
和begin
。出于此名称查找的目的,namespace std是一个关联的命名空间。