Подтвердить что ты не робот

С++ 11 Измените `auto` 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 или lambdas. Спасибо.

4b9b3361

Ответ 1

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

std::function<bool()> a = [] { return true; };
a = [] { return false; };

Ответ 2

Lambda может быть преобразован в указатель функции, используя унарный оператор +, например:

+[]{return true;}

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

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

В вашем случае

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

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

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


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

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

Ответ 3

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

std::function <bool ()> a = [] { return true; };
a = [] { return false; };

Ответ 4

Мы можем использовать ретроспективный вызов для преобразования лямбда в 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 type):

auto a = FFL([] { return false; });
a = FFL([] { return true; });

Ответ 5

Так как 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; };

Это пригодится с более сложными сигнатурами и даже более с выведенными типами возврата.