35

The error reads:

request for member 'begin', 'end' in 'arr' which is non class type int[5], unable to deduce from expression error.

My code:

#include <iostream>
using namespace std;

int main()
{
    int * mypointer;

    int arr[5] = {1,3,5,7,9};

    mypointer = arr;

    for(auto it = arr.begin(); it != arr.end(); ++it) {
        cout<<*mypointer<<endl;

        mypointer++;
    }

    return 0;
}
GManNickG
  • 494,350
  • 52
  • 494
  • 543
Sal Rosa
  • 551
  • 2
  • 8
  • 12
  • 13
    Try replacing `arr.begin()` and `arr.end()` with `std::begin(arr)` and `std::end(arr)` – Joe Jan 30 '13 at 01:44
  • How did your favourite C++ book give you the impression calling a member function on an array was even possible? Besided that, what is the actual question (if it is *"is this possible"*, then the compiler already gave it, if it is *"how is this possible otherwise"*, then *ask an actual question*)? – Christian Rau Jan 30 '13 at 09:24
  • See also https://stackoverflow.com/questions/7593086/why-use-non-member-begin-and-end-functions-in-c11 In that question it is pointed out that Herb Sutter prefers the free functions to the class methods, to enhance generality. – Matthew Hannigan Jan 21 '18 at 04:36

6 Answers6

58

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()
}
GManNickG
  • 494,350
  • 52
  • 494
  • 543
5

For a standard fixed-length C array, you can just write

int c_array[] = {1,3,5,7,9}, acc = 0;

for (auto it : c_array) {
    acc += it;
}

The compiler does the behind-the-scenes work, eliminating the need to create all those begin and end iterators.

user1329482
  • 569
  • 3
  • 8
  • 1
    You need to have included header for this to work. Otherwise, you would get an error like `error: 'begin' was not declared in this scope: for(auto it : c_array){` – varsh Jan 22 '19 at 08:40
  • 1
    @varsh I could use it without including `iterator` – MorganStark47 Apr 23 '21 at 10:49
0

In C++, arrays are not classes and therefore do not have any member methods. They do behave like pointers in some contexts. You can take advantage of this by modifying your code:

#include <iostream>
using namespace std;

int main()
{
    int * mypointer;

    const int SIZE = 5;
    int arr[SIZE] = {1,3,5,7,9};

    mypointer = arr;

    for(auto it = arr; it != arr + SIZE; ++it) {
        cout<<*mypointer<<endl;

        mypointer++;
    }

    return 0;
}

Of course, this means that mypointer and it both contain the same address, so you don't need both of them.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
0

One thing I'd like to point out for you is that you really don't have to maintain a separate int* to use in dereferencing the array elements, apart from the whole member thing others have well pointed out.

Using a more modern approach, the code is both more readable, as well as safer:

#include <iostream>
#include <algorithm>
#include <array>
#include <iterator>
using namespace std;

int main()
{
    std::array<int, 5> cpp_array{1,3,5,7,9};

    // Simple walk the container elements.
    for( auto elem : cpp_array )
        cout << elem << endl;

    // Arbitrary element processing on the container.
    std::for_each( begin(cpp_array), end(cpp_array), [](int& elem) {
        elem *= 2;      // double the element.
        cout << elem << endl;
    });
}

Using the lambda in the second example allows you to conveniently perform arbitrary processing on the elements, if needed. In this example, I'm just showing doubling each element, but you can do something more meaningful within the lambda body instead.

Hope this makes sense and helps.

0

Perhaps here is a cleaner way to do it using templates and lambdas in c++14:

Define:

template<typename Iterator, typename Funct>
void my_assign_to_each(Iterator start, Iterator stop, Funct f) {
    while (start != stop) {
        *start = f();
        ++start;
    }
}

template<typename Iterator, typename Funct>
void my_read_from_each(Iterator start, Iterator stop, Funct f) {
    while (start != stop) {
        f(*start);
        ++start;
    }
}

And then in main:

int x[10];
srand(time(0));
my_assign_to_each(x, x+10, [] () -> int { int rn{}; rn = rand(); return rn; });
my_read_from_each(x, x+10, [] (int value) { std::cout << value << std::endl; });

int common_value{18};
my_assign_to_each(x, x+10, [&common_value] () -> int { return common_value; });
my_read_from_each(x, x+10, [] (int value) { std::cout << value << std::endl; });
  • 2
    `my_assign_to_each` a.k.a. [`std::generate`](http://en.cppreference.com/w/cpp/algorithm/generate), `my_read_from_each` a.k.a. [`std::for_each`](http://en.cppreference.com/w/cpp/algorithm/for_each). Also `std::generate(x, x+10, rand);` – Caleth Jan 25 '18 at 16:29
0

Quite late but I think it's worth to mention that:

void findavgTime(int n)
{
    int wt1[n];
    fill_wt(wt1,n); //Any method that puts the elements into wt1
    int wt2[3];
    int sum  = accumulate(begin(wt1), end(wt1), 0); // Fails but wt2[3] will pass. Reason: variable-sized array type ‘int [n]’ is not a valid template argument)
}
Kumar Roshan Mehta
  • 3,078
  • 2
  • 27
  • 50