GKxx
GKxx

Reputation: 373

What does range-for loop exactly do?

I'm working on a snake game program. I use a deque of Body in class Snake to represent a snake and of course Body is a struct I have defined. Here is part of the code:

struct Body {        // one part of snake body
    int x, y, direction;
    Body() : x(0), y(0), direction(UP) { }
    Body(int ix, int iy, int id) : x(ix), y(iy), direction(id) { }
};

class Snake {
protected:
    std::deque<Body> body;
    // other members
public:
    auto begin()->std::deque<Body>::const_iterator const { return body.cbegin(); }
    auto end()->std::deque<Body>::const_iterator const { return body.cend(); }
    // other members
};

And in another function construct_random_food I need to generate a food and make sure it does not coincide with the snake. Here's the function definition:

Food construct_random_food(int gameSize, const Snake& snake) {
    static std::random_device rd;
    static std::uniform_int_distribution<> u(2, gameSize + 1);
    static std::default_random_engine e(rd());
    Food f;
    while (1) {
        f.x = u(e) * 2 - 1;
        f.y = u(e);
        bool coincide = 0;
        for (const auto& bd : snake) // This causes an error.
            if (bd.x == f.x && bd.y == f.y) {
                coincide = 1; break;
            }
        if (!coincide) break;
    }
    return f;
}

An error is caused at the range-based for-loops line. It says that I'm trying to cast const Snake to Snake& (casting a low-level const away). I fix the problem by rewriting that line like this:

for (const auto& fd : const_cast<Snake&>(snake))

So I'm wondering what exactly a range-for do and what it needs. Does the error have anything to do with the begin() function in class Snake?

Upvotes: 0

Views: 111

Answers (1)

Benjamin Lindley
Benjamin Lindley

Reputation: 103703

The problem is that your begin and end functions are not const.

auto begin()->std::deque<Body>::const_iterator const { return body.cbegin(); }
            // this applies to the return type ^^^^^

You've applied the const qualifier to the return type, not to the calling object. Put the const qualifier before the trailing return type.

auto begin() const ->std::deque<Body>::const_iterator { return body.cbegin(); }

You can see the correct order in which you should place function qualifiers here: http://en.cppreference.com/w/cpp/language/function

Upvotes: 7

Related Questions