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

2020-02-03 10:26发布

问题:

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

回答1:

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


回答2:

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.



回答3:

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.



回答4:

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.



回答5:

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


回答6:

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