Включение на основе диапазона для типа, который имеет переменную-член "конец" - PullRequest
4 голосов
/ 03 мая 2019

Я работаю с векторным типом , который приходит из библиотеки C и выглядит как

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

Я попытался включить цикл for на основе диапазона для этого типа, создав бесплатные функции begin() и end(), но я получаю эту ошибку от clang:

ошибка: тип диапазона 'igraph_vector_int_t' имеет элемент 'end', но нет элемента 'begin'

Есть ли способ (с помощью C ++ 11) включить циклы на основе диапазона для такого типа (который я не могу изменить напрямую)?


Вот минимальный пример, демонстрирующий проблему:

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

Ошибка от 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

1 Ответ

6 голосов
/ 03 мая 2019

g++ 8.x и clang++ 8.x (и новее) скомпилируют ваш код: живой пример на godbolt.org .

Вероятно, это ошибка компилятора.


Как Франсуа Андриё , упомянутый в комментариях, Стандарт гласит:

[stmt.ranged]

1.2.2 , если for-range-initializer является выражением типа класса C, безусловные идентификаторы begin и end ищутся в область действия C как при поиске доступа к члену класса ([basic.lookup.classref]), и если оба найдут хотя бы одно объявление, begin-expr и end-expr являются range.begin() и range.end() соответственно;

1.3.3 в противном случае begin-expr и end-expr равны begin(range) и end(range) соответственно, где ищутся начало и конец вверх в связанных пространствах имен ([basic.lookup.argdep]). [Примечание: обычный неквалифицированный поиск ([basic.lookup.unqual]) не выполняется. - конец примечания]

Кажется, это согласуется с моей гипотезой, что это ошибка. Если найден только один из .begin и .end, то 1.3.3 должен сделать ваш код правильно сформированным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...