Ответ 1
Это ошибка VS. Код отлично сформирован.
Правило в [expr.prim.lambda]:
Если лямбда-выражение или экземпляр шаблона оператора вызова функции общего лямбда odr использует (3.2) это или переменную с автоматическим временем хранения от ее области охвата, это лицо должно быть захваченным лямбда-выражением.
Если переменная используется odr, если, согласно [basic.def.odr]:
Переменная x, имя которой отображается как потенциально оцененное выражение ex, является odr, используемое ex , если применение преобразования lvalue-to-rvalue (4.1) к x не дает постоянного выражения (5.20) что не вызывает никаких нетривиальных функции, и, если x является объектом, ex является элементом множества потенциальных результатов выражения e, где либо преобразование lvalue-to-rval (4.1) применяется к e, либо e является выражением отбрасываемого значения (раздел 5).
И, из [expr.const]:
Условное выражение e является выражением постоянной константы, если оценка e, следуя правилам абстрактная машина (1.9), оценила бы одно из следующих выражений: [...] преобразование lvalue-to-rvalue (4.1), если оно не применяется к нелетучими значениям целого или перечисляемого типа, которые относятся к полному не- -устойчивый объект const с предшествующей инициализацией, инициализированный константным выражением
В:
return item == controlValue;
controlValue
- это значение целочисленного типа, которое относится к полному нелетучивому объекту const, инициализированному константным выражением. Следовательно, когда мы используем controlValue
в контексте, который включает преобразование lvalue-to-rvalue, он не используется odr. Поскольку он не используется не-odr, нам не нужно его захватывать.
Когда вы изменили controlValue
на non const
, оно перестает быть постоянным выражением, а проверка равенства odr - использует его. Так как он не захвачен, а используется odr, лямбда плохо сформирована.
Обратите внимание, что именно такой пример появляется в стандарте:
void f(int, const int (&)[2] = {}) { } // #1
void f(const int&, const int (&)[1]) { } // #2
void test() {
const int x = 17;
auto g = [](auto a) {
f(x); // OK: calls #1, does not capture x
};
// ...
}