void f( int , const int (&)[2] = {}) { } // #1
void f( int , const int (&)[1] ) { } // #2
// void f(const int&, const int (&)[1] ) { } // #2_original
void test() {
const int x = 17;
auto g = [](auto a) {
f(x); // OK: calls #1, does not capture x
};
auto g2 = [ /* = */ ](auto a) {
int selector[ sizeof(a) == 1 ? 1 : 2 ]{};
f(x, selector); // OK: is a dependent expression, so captures x ???
};
}
Это пример из стандарта С++ 14 (ISO/IEC 14882:2014), раздел 5.1.2, параграф 12, который я изменил двумя способами:
- Во-первых, обе версии функции
f()
имеютint
в качестве первого аргумента, поэтому переменнаяx
в любом случае не odr-используется. - Во-вторых, я удалил (закомментировал) capture-default в лямбда-выражении
g2
.
Соответствует ли этот код стандарту? И clang, и gcc успешно компилируются. Однако в исходном примере лямбда g2
имела capture-default ([=]
), поэтому переменная x
была неявно захвачена, поскольку было зависимое выражение (а также потому, что она могла быть odr-used< /em> в функции f() #2_original
). Обратите внимание, что в вышеупомянутом параграфе Стандарта есть 2 условия для неявного захвата переменной x
(odr-use зависимое выражение). Теперь без capture-default и odr-use:
Не должно ли это быть ошибкой времени компиляции, поскольку есть зависимое выражение и нет capture-default? То есть переменная
x
должна быть захвачена, но это невозможно (предположим, чтоg2
вызывается с обоими типами аргументов, т. е. одни возвращаютsizeof(a)=1
, а другиеsizeof(a)>1
).Или условие зависимого выражения для неявного захвата переменной применяется только при наличии capture-default? Это означает, что без odr-use (т. е. без
const int&
в функцииf() #2
) программа будет работать одинаково независимо от capture-default. Следовательно, не будет ли бесполезным второе условие относительно зависимого выражения?
Это стандарт С++ 14 (ISO/IEC 14882:2014), раздел 5.1.2, пункт 12 (выделено мной):
лямбда-выражение со связанным capture-default, которое явно не фиксирует this или переменную с автоматическим сохранением длительность (это исключает любое выражение-id-выражение, которое, как было обнаружено, ссылается на нестатический элемент данных, связанный с init-capture), считается неявно захватить объект (т. е. это или переменную), если составной оператор:
- odr-использует (3.2) сущность, или
- называет сущность в потенциально вычисляемом выражении (3.2), где объемлющее полное выражение зависит от универсального лямбда-параметра, объявленного в пределах досягаемости лямбда-выражения.
Примечание: лямбда g
не захватывает переменную x
, потому что она не odr-используется в f(x)
(см. Стандарт C++14 (ISO/IEC 14882:2014), раздел 5.1.2, параграф 13).
Ссылки: