#gcc #lambda #clang #c 14 #language-lawyer
#gcc #лямбда #лязг #c 14 #язык-юрист
Вопрос:
Я обнаружил проблему, которая, как я предполагаю, связана с ошибкой в GCC.
В любом случае, прежде чем открывать проблему, я хотел бы быть уверенным.
Рассмотрим приведенный ниже код:
#include<algorithm>
#include<list>
template<typename U>
struct S {
using FT = void(*)();
struct T { FT func; };
template<typename>
static void f() { }
std::list<T> l{ { amp;f<int> }, { amp;f<char> } };
void run() {
l.remove_if([](const T amp;t) { return t.func == amp;f<int>; }); // (1)
l.remove_if([](const auto amp;t) { return t.func == amp;f<int>; }); // (2)
}
};
int main() {
S<void> s;
s.run();
}
clang v3.9 компилирует оба (1) и (2), как и ожидалось.
GCC v6.2 компилирует (1), но не компилирует (2) .
Возвращаемая ошибка:
ошибка: ‘f’ не был объявлен в этой области
Более того, обратите внимание, что GCC компилирует (2), если он изменен следующим образом:
l.remove_if([](const auto amp;t) { return t.func == amp;S<U>::f<int>; }); // (2)
Насколько я знаю, использование const auto amp;
вместо const T amp;
не должно изменять поведение в этом случае.
Это ошибка GCC?
Комментарии:
1. Мне интересно, в какой области компилятор генерирует класс, представляющий общий лямбда: file-scope, class-scope, function-scope (как локальный класс, но который не поддерживает шаблон функции в качестве члена)?
2. Отсюда — тип закрытия объявляется в наименьшей области блока, области класса или области пространства имен, которая содержит соответствующее лямбда-выражение . Я бы сказал
S<U>
, вот почему я думаю, что это ошибка, и она должна видеть объявлениеf
.3. @Nawaz Может быть, это даже более уместно — область охвата локального лямбда-выражения — это набор охватывающих областей вплоть до самой внутренней охватывающей функции и ее параметров ?
4. @skypjack хм, если вы удалите внешний шаблон (
typename <class U>
), он также будет скомпилирован…5. @W.F. Да, конечно, я это заметил. Минимальный, рабочий пример действительно минимальный !! Я сделал все возможное. 😉
Ответ №1:
Согласно [expr.prim.lambda]:
8 — […] [Для] целей поиска имени (3.4) […] составное выражение рассматривается в контексте лямбда-выражения. […]
MCVE:
template<int>
struct S {
template<int> static void f();
S() { void(*g)(char) = [](auto) { f<0>; }; }
};
S<0> s;
Добавление составного оператора к контексту лямбда-выражения дает четко действительную программу:
template<int>
struct S {
template<int> static void f();
S() { f<0>; }
};
S<0> s;
Так что да, это ошибка в gcc.