begin()和end()函数不应该是模板类Vector的成员函数吗?

时间:2013-08-01 12:45:08

标签: c++ templates c++11 auto

提交人

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

3 个答案:

答案 0 :(得分:5)

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

  • 如果使用的类型是一个类,它将首先在该类的范围内查找成员函数beginend

  • 如果类型不是类或没有此类成员函数,则按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-exprend-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是一个关联的命名空间。

  •