Cannot Use .Begin() or .End() on an Array

Cannot use .begin() or .end() on an array

Arrays have no member functions as they aren't a class type. This is what the error is saying.

You can use std::begin(arr) and std::end(arr) from the <iterator> header instead. This also works with types that do have .begin() and .end() members, via overloading:

#include <array>
#include <vector>

#include <iterator>

int main()
{
int c_array[5] = {};
std::array<int, 5> cpp_array = {};
std::vector<int> cpp_dynarray(5);

auto c_array_begin = std::begin(c_array); // = c_array + 0
auto c_array_end = std::end(c_array); // = c_array + 5

auto cpp_array_begin = std::begin(cpp_array); // = cpp_array.begin()
auto cpp_array_end = std::end(cpp_array); // = cpp_array.end()

auto cpp_dynarray_begin = std::begin(cpp_dynarray); // = cpp_dynarray.begin()
auto cpp_dynarray_end = std::end(cpp_dynarray); // = cpp_dynarray.end()
}

Can std::begin work with array parameters and if so, how?

Yes, std::begin and std::end can work with parameters that are C style arrays.

The trick is in passing a parameter that's a C style array. When you specify a 1D array as a normal parameter to a normal function, its type is silently adjusted from "array of T" to "pointer to T". When you call that function, what gets passed isn't the array (as an array), but a pointer to the first element of the array.

It is, however, possible to pass an array by reference to a function template:

template <class T, size_t N>
void function(T (&array)[N]) {
// function body here
}

In this case, where you're passing an actual array (albeit, by reference) rather than a pointer, you can use std::begin and std::end perfectly well. For example:

template <class T, size_t N>
T sum(T (&array)[N]) {
return std::accumulate(std::begin(array), std::end(array), T());
}

Now passing an array is trivial, such as:

int array[] = {1, 2, 3, 4};

auto total = sum(array);

std::begin and std::end themselves are (or at least can be) implemented similarly to sum--the array is passed by reference, so they can look something like this:

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

template <class T, size_t N>
T *end(T (&array)[N]) {
return array + N;
}

Note that although these were added to the standard more recently, they don't require any particularly tricky use of templates, so the implementation above should work fine with a plain old C++98 compiler (and, if memory serves, even with pre-standard compilers such as VC++ 6).

begin and end function for built-in array types

The problem that the compiler faces, is that it has no way to guess the size of argv, because it is not an array but a mere pointer.

Arrays can always be used as pointers, because an array can decay to a pointer to its first element. But the inverse is false! You can access the elements of an array through the array or through a pointer exactly the same, but the pointer and the array are not the same:

int a[5];
int *p = a; // p[i] and a[i] are now the same
size_t s = sizeof(a); // s is 5 * sizeof(int) 20 on common (32 bits) architectures
size_t s2 = sizeof(p); // s2 is just sizeof(int *) 4 on 32 bits architecture

The convention says that argv has argc elements (and that argv[argc] is a null pointer). But std::begin and std::end do not make use of that convention. So do it by hand as a nice programmer:

#include <iostream>
#include <iterator>

int main(int argc,char *argv[])
{
char **first=argv,**last=argv + argc;
}

std::begin and std::end not working with pointers and reference why?

Given just a pointer to the start of an array, there's no way to determine the size of the array; so begin and end can't work on pointers to dynamic arrays.

Use std::vector if you want a dynamic array that knows its size. As a bonus, that will also fix your memory leak.

The third case fails because, again, you're using (a reference to) a pointer. You can use a reference to the array itself:

int (&refOfFirst)[3] = first;

or, to avoid having to specify the array size:

auto & refOfFirst = first;

and begin and end will work on this exactly as they would work on first itself.

Use std::begin(), std::end() to convert ArrayXd to stl vector,

std::begin(vec.data()) cannot work because data() returns a raw pointer which cannot convey the number of elements in the vector. This version is the best one of yours:

std::vector<double> my_vec(e_array.data(), e_array.data() + 5);

And slightly better:

std::vector<double> my_vec(e_array.data(), e_array.data() + e_array.size());

And you may also be able to do this with many containers, but not with Eigen's ArrayXd in particular, because it lacks begin() and end() (related: http://eigen.tuxfamily.org/bz/show_bug.cgi?id=231).

std::vector<double> my_vec(foo.begin(), foo.end());


Related Topics



Leave a reply



Submit