С++ 11 Изменить `auto` Lambda на другую Lambda?

Скажем, у меня есть следующая переменная, содержащая лямбда:

auto a = [] { return true; };

И я хочу, чтобы a позже вернулся false. Могу ли я сделать что-то в этом роде?

a = [] { return false; };

Этот синтаксис дает мне следующие ошибки:

binary '=' : no operator found which takes a right-hand operand of type 
'main::<lambda_a7185966f92d197a64e4878ceff8af4a>' (or there is no acceptable conversion)

IntelliSense: no operator "=" matches these operands
        operand types are: lambda []bool ()->bool = lambda []bool ()->bool

Есть ли способ добиться чего-то подобного? Я хотел бы изменить переменную auto на другую лямбду. Я относительно новичок, поэтому мне может не хватать некоторых знаний о auto или лямбдах. Спасибо.


person Archie Gertsman    schedule 27.07.2016    source источник
comment
Есть решение bool b = true; auto a = [&b] { return b; }; b = false;, но оно, конечно, не распространяется на все ситуации.   -  person MSalters    schedule 28.07.2016


Ответы (5)


Каждое лямбда-выражение создает новый уникальный тип, поэтому тип вашей первой лямбды отличается от типа вашей второй (пример). Кроме того, оператор присваивания копии лямбда определяется как удаленный (пример), поэтому вы вдвойне не можете сделай это. Для аналогичного эффекта вы можете сделать a объектом std::function, хотя это будет стоить вам некоторой производительности.

std::function<bool()> a = [] { return true; };
a = [] { return false; };
person Ryan Haining    schedule 27.07.2016

Лямбда может быть преобразована в указатель функции с помощью унарного оператора + следующим образом:

+[]{return true;}

пока группа захвата пуста и не имеет auto аргументов.1

Если вы сделаете это, вы можете назначить разные лямбда-выражения одной и той же переменной, если все лямбда-выражения имеют одинаковую сигнатуру.

В твоем случае,

auto a = +[]{return true;};
a = +[]{return false;};

Живой пример на Coliru

будет и компилироваться, и действовать так, как вы ожидаете.2 Вы можете использовать указатели функций так же, как вы ожидаете использовать лямбда, поскольку оба будут действовать как функторы.


1. В C++14 вы можете объявлять лямбда-выражения с auto в качестве типа аргумента, например [](auto t){}. Это общие лямбда-выражения с шаблоном operator(). Поскольку указатель функции не может представлять шаблонную функцию, трюк + не будет работать с общими лямбда-выражениями.

2. Технически вам не нужен второй оператор + в задании. Лямбда будет преобразована в тип указателя функции при назначении. Однако мне нравится последовательность.

person jaggedSpire    schedule 27.07.2016
comment
Момент, когда C++ официально вошел в мир Perl! - person peppe; 27.07.2016
comment
@jaggedSpire Мне это так сильно нужно было много раз, и я думал, что единственным решением были другие function ответы на этот вопрос. Как вы узнали об этом? Я никогда не видел его раньше. - person Jonathan Mee; 23.08.2016
comment
@JonathanMee Я на самом деле нашел его, перейдя по соответствующей ссылке на боковой панели, когда-то давно: Положительная лямбда: +[]{} - Что это за колдовство?< /а> - person jaggedSpire; 23.08.2016

Каждая лямбда имеет свой тип, поэтому вы не можете изменить его. Вы можете использовать std::function для хранения произвольного вызываемого объекта, который можно изменить по желанию.

std::function <bool ()> a = [] { return true; };
a = [] { return false; };
person nate    schedule 27.07.2016
comment
Думаю, Райан опередил вас, опубликовав то же самое. Но у вас не хватает точки с запятой. - person JDługosz; 28.07.2016

Мы можем использовать ретроспективный вызов для преобразования лямбда в std::function:

template<typename T>
struct memfun_type
{
  using type = void;
};

template<typename Ret, typename Class, typename... Args>
struct memfun_type<Ret(Class::*)(Args...) const>
{
  using type = std::function<Ret(Args...)>;
};

template<typename F>
typename memfun_type<decltype(&F::operator())>::type
FFL(F const &func)
{ // Function from lambda !
  return func;
}

После этого мы сможем сделать (поскольку 'a' теперь является типом std::function ):

auto a = FFL([] { return false; });
a = FFL([] { return true; });
person Alex Melnikov    schedule 18.10.2017
comment
Немного больше объяснений было бы неплохо. - person J...S; 18.10.2017

Начиная с C++17 вы можете вывести параметр шаблона std::function благодаря выводу аргумента шаблона класса . Он даже работает с захватом лямбд:

int a = 24;

std::function f = [&a] (int p) { return p + a; };
f               = [&a] (int p) { return p - a; };
f               = []   (int p) { return p; };

Это удобно с более сложными подписями и еще больше с выведенными типами возвращаемых значений.

person bolov    schedule 22.01.2018