Shouldn't the begin() and end() functions be member functions of the template class Vector?

StackOverflow https://stackoverflow.com/questions/17994460

  •  04-06-2022
  •  | 
  •  

Domanda

In page 82 of the draft of Chapter 3 : A Tour of C++: Abstraction Mechanisms the author writes:

If we also want to use the range-for loop for our Vector, we must define suitable begin() and end() functions:

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
}

Given those, we can write:

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

Notice that the class template Vector is defined in page 81 of the draft.

È stato utile?

Soluzione

For range-based for to work, the compiler needs to find a suitable function to get the iterators.

  • If the type used is a class, it'll first look for member functions begin and end in the scope of that class.

  • If the type is not a class or the are no such member functions, it looks them up by Argument Dependent Lookup.

This is the reason range-based for works on C-arrays. Obviously, arrays can't have member functions, so standard library provides two functions defined similarly to this:

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

and similarly for end.

To answer your question from the title: they can be, but it's not a neccesity. You can define free functions in the same namespace as your class and they'll be found.

Altri suggerimenti

If it is not an array or a container with .begin() and .end() it will look up by Argument dependent name.

It is said here :

Keep in mind these facts about range-based for:

  • Automatically recognizes arrays.

  • Recognizes containers that have .begin() and .end().

  • Uses argument-dependent lookup begin() and end() for anything else.

In such a range based for:

for ( for-range-declaration : expression ) statement

the standard says that the compiler looks for either members ((expression).begin(), (expression).end()) or free functions (begin((expression)), end((expression))) if expression is of class type.

Therefore you can either provide member functions OR free functions (which need to be in scope for argument dependant lookup).

C++11, § 6.5.4 [stmt.ranged]

This is what a ranged-based for does according to the standard:

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
  }
}

The begin-expr and end-expr are described as:

  • if _RangeT is an array type, begin-expr and end-expr are _range and _range + _bound, respectively, where _bound is the array bound. If _RangeT is an array of unknown size or an array of incomplete type, the program is ill-formed;

  • if _RangeT is a class type, the unqualified-ids begin and end are looked up in the scope of class _RangeT as if by class member access lookup (3.4.5), and if either (or both) finds at least one declaration, beginexpr and end-expr are __range.begin() and __range.end(), respectively;

  • otherwise, begin-expr and end-expr are begin(__range) and end(__range), respectively, where begin and end are looked up with argument-dependent lookup (3.4.2). For the purposes of this name lookup, namespace std is an associated namespace.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top