Szabolcs
Szabolcs

Reputation: 25703

Enabling range-based for for type that has "end" member variable

I am working with a vector type that comes from a C library and looks similar to

struct Vec {
    int *stor_begin;
    int *stor_end;
    int *end;
};

I tried to enable range-based for loop for this type by creating free begin() and end() functions, but I am getting this error from clang:

error: range type 'igraph_vector_int_t' has 'end' member but no 'begin' member

Is there a way (using C++11) to enable range-based for loops for such a type (which I cannot modify directly)?


Here is a minimal example that demonstrates the problem:

// No problems with Foo

struct Foo {
    int *fooBeg;
    int *fooEnd;
};

int *begin(Foo &foo) { return foo.fooBeg; }
int *end(Foo &foo) { return foo.fooEnd; }

void testFoo(Foo &foo) {
    int sum = 0;
    for (const auto &x : foo)
        sum += x;
}

// Bar does not work because it has a member variable called 'end'

struct Bar {
    int *stor_begin;
    int *end;
};

int *begin(Bar &bar) { return bar.stor_begin; }
int *end(Bar &bar) { return bar.end; }

void testBar(Bar &bar) {
    int sum = 0;
    for (const auto &x : bar)
        sum += x;
}

Error from gcc 7.2 / Wandbox:

prog.cc: In function 'void testBar(Bar&)':
prog.cc:26:26: error: range-based 'for' expression of type 'Bar' has an 'end' member but not a 'begin'
     for (const auto &x : bar) {
                          ^~~
prog.cc:26:26: error: expression cannot be used as a function

Upvotes: 4

Views: 168

Answers (1)

Vittorio Romeo
Vittorio Romeo

Reputation: 93264

g++ 8.x and clang++ 8.x (and newer) both compile your code: live example on godbolt.org.

This is very likely to be a compiler bug.


As François Andrieux mentioned in the comments, the Standard says:

[stmt.ranged]

1.2.2 if the for-range-initializer is an expression of class type C, the unqualified-ids begin and end are looked up in the scope of C as if by class member access lookup ([basic.lookup.classref]), and if both find at least one declaration, begin-expr and end-expr are range.begin() and range.end(), respectively;

1.3.3 otherwise, begin-expr and end-expr are begin(range) and end(range), respectively, where begin and end are looked up in the associated namespaces ([basic.lookup.argdep]). [ Note: Ordinary unqualified lookup ([basic.lookup.unqual]) is not performed. — end note ]

This seems to agree with my hypothesis of this being a bug. If only one of .begin and .end is found, then 1.3.3 should make your code well-formed.

Upvotes: 6

Related Questions