Ответ 1
Я считаю, что оба компиляторы ошибочны для (A) и gcc неправильно для (D).Забастовкa >
Я считаю, что gcc неправильно для (A) и (D), в то время как clang является правильным для обоих.
Соответствующие разделы [expr.lambda.prim]:
Выполнение init-capture ведет себя так, как будто оно объявляет и явно фиксирует переменную формы "auto init-capture"; чья декларативная область является составным выражением лямбда-выражений, за исключением того, что:
- если захват копируется (см. Ниже), нестатический член данных, объявленный для захвата, и переменная рассматривается как два разных способа обращения к одному и тому же объекту, который имеет время жизни нестатический элемент данных, и никакая дополнительная копия и уничтожение не выполняются,
и
Каждое id-выражение внутри составного оператора лямбда-выражения , которое является неприемлемым (3.2) объект, захваченный копией, преобразуется в доступ к соответствующему неназванному элементу данных тип закрытия.
decltype(j)
не является нечетным использованием j
, поэтому такое преобразование не следует рассматривать. Таким образом, в случае [=]{...}
, decltype(j)
должен давать int&
. Однако в случае init-capture поведение выглядит так, как если бы существовала переменная формы auto j = j;
, а переменная j
относится к одному и тому же неназванному нестатическому элементу данных без необходимости такого преобразования. Поэтому в случае [j=j]{...}
, decltype(j)
должен указывать тип этой переменной - int
. Это определенно не const int
. Это ошибка.
Следующий соответствующий раздел:
Каждое вхождение
decltype((x))
, гдеx
- это, возможно, заключенное в скобки id-выражение, которое называет сущность с продолжительностью автоматического хранения, обрабатывается так, как если быx
были преобразованы в доступ к соответствующему элементу данных типа закрытия, было бы объявлено, еслиx
было odr-использованием обозначенного объекта. [Пример:void f3() { float x, &r = x; [=] { // x and r are not captured (appearance in a decltype operand is not an odr-use) decltype(x) y1; // y1 has type float decltype((x)) y2 = y1; // y2 has type float const& because this lambda // is not mutable and x is an lvalue decltype(r) r1 = y1; // r1 has type float& (transformation not considered) decltype((r)) r2 = y2; // r2 has type float const& } }
-end пример]
В примере далее показано, что decltype(j)
должен быть int&
в неявном экземпляре копии, а также демонстрирует, что decltype((j))
обрабатывается так, как если бы x
были соответствующим членом данных, который был бы объявлен: который равен int const&
в обоих случаях (поскольку лямбда не mutable
и j
- значение l). Ваши (C) и (D) случаи точно отражают объявления r1
, r2
в примере. Который, хотя примеры не являются нормативными, безусловно, предполагает, что gcc ошибается в том, что имеет другое поведение.