Home > Enterprise >  C Function that accepts array.begin() and array.end() as arguments
C Function that accepts array.begin() and array.end() as arguments

Time:12-11

I want my function to be able to take array.begin() and array.end() as arguments. As far as I understand, the begin/end functions return a pointer to the first/last element of the array. Then why does the following code not work? How should I write the code instead?

#include <iostream>
#include <array>

template<class T> void foo(const T* begin, const T* end) {
     ...
}

int main() {
     std::array<int, 5> arr = { 1, 2, 3, 4, 5 };
     foo(arr.begin(), arr.end());          // <-- error!

     return 0;
}

CodePudding user response:

As far as I understand, the begin/end functions return a pointer to the first/last element of the array

No. begin and end return iterators. The standard library works with iterators. Iterators are a generalization of pointers.

Iterators behave like pointers and you use them like pointers (e.g. *it to access the element), with some caveats: not all iterators have all the operations a pointer does. A pointer satisfies the random access iterator concept, so on some implementations the iterator of std::array could be just an alias for the pointer type, but you can't rely on that. E.g. on the same compiler it can be a pointer for the release build, but a full class for the debug build.

The idiomatic way is to write:

template<class It>
void foo(It begin, It end) {
     for (auto it = begin; it != end;   it) {
          const auto& elem = *it;
          // ..
     }
}

Since C 20 we should transition from iterator pairs to ranges:

void foo(std::ranges::range const auto& r) {
    for (const auto& elem : r) { 
        // ...
    }
}

CodePudding user response:

As far as I understand, the begin/end functions return a pointer

Your understanding is (generally) wrong. begin and end functions return std::array::iterator, as per documentation. That type is not necessarily a pointer.

to the first/last element of the array

end isn't an iterator to the last element, but one past the last element.

how to solve my problem the right way?

Accept arguments of type std::array::iterator.

That said, given that foo is a template, there seems to be little reason to not allow the argument to be of any iterator type:

template<class It> 
void
foo(It begin, It end)

Alternatively, you could accept a range:

template<class Range> 
void
foo(const Range& range)

// usage
foo(arr);
  •  Tags:  
  • c
  • Related