Инициализация захвата лямбда в тройном операторе
Я хотел создать лямбда следующим образом:
auto l1 = condition ?
[](){ return true; } :
[number](){ return number == 123; };
Однако я получил ошибку:
operands to ?: have different types ‘main()::<lambda()>’ and ‘main()::<lambda()>’
Очевидно, что типы кажутся одинаковыми. Я думал, что захват number
только в одном из lambdas может быть проблемой, но я получаю для них ту же ошибку:
//check if capturing number in both lambdas would help
auto l2 = condition ?
[number](){ return true; } :
[number](){ return number == 123; };
//maybe the first lambda capture was optimised out? let make sure:
auto l3 = condition ?
[number](){ return number != 123; } :
[number](){ return number == 123; };
Я знаю, что могу сделать это иначе (ниже), но мне интересно, в чем причина такого поведения. Он был скомпилирован с включенным GCC6.3.1, С++ 14.
//compiles
auto l4 = condition ?
[](const int){ return true; } :
[](const int number){ return number == 123; };
Ответы
Ответ 1
Каждое выражение лямбда имеет уникальный тип (т.е. тип закрытия, который является уникальным неназванным не-объединенным неагрегатным типом класса) даже с тем же сигнатурным и функциональным телом; компилятор просто не может вывести общий тип тернарный условный оператор для переменной, объявленной auto
, два типа закрытия не имеют значения при все.
Вместо этого вы можете использовать std::function
. например.
std::function<bool()> l1;
if (condition)
l1 = [](){ return true; };
else
l1 = [number](){ return number == 123; };
Для l4
обратите внимание, что лямбда-выражение с пустым списком захвата может быть неявно преобразовано в соответствующий указатель функции. В этом случае оба они могут быть преобразованы в один и тот же тип указателя функции (т.е. bool(*)(int)
), который затем можно было бы вывести как общий тип тернарного условного оператора и тип l4
.
Ответ 2
Если вы действительно хотите использовать условный оператор, вы можете сделать это следующим образом:
auto l1 = condition
? std::function<bool()>{[](){ return true; }}
: std::function<bool()>{[number](){ return number == 123; }};
В С++ 17 это можно упростить благодаря Вывод аргумента шаблона шаблона:
auto l1 = condition
? std::function{[](){ return true; }}
: std::function{[number](){ return number == 123; }};
Ответ 3
Лямбда в С++ - это экземпляр контракта-функтора, реализующего локальный класс. Я имею в виду operator() и т.д. И эти классы не связаны и имеют разные типы.
Ваш код эквивалентен
struct l1 {
bool operator () const {
return true;
}
};
struct l2 {
private int number_:
l2(int number): number_(number){}
bool operator () const {
return number_ == 123;
}
};
int number = ???
auto l3 = condition ? l1 : l2(number);