Что происходит, когда назначается тип, содержащий лямбду? - PullRequest
10 голосов
/ 13 декабря 2011

Скажем, у меня есть какой-то тип, заключающий функцию, может быть, лямбда-функцию:

template<typename Function>
  struct my_struct
{
  Function f;

  my_struct(const Function &f) : f(f) {}
};

Что происходит, когда назначается экземпляр этого типа? Насколько я понимаю, лямбды неизменны и удалили операторы присваивания.

Тем не менее, когда я присваиваю объекту этот тип в приведенном ниже фрагменте кода, ошибка не выдается:

// a structure which contains a function;
// possibly a lambda function
template<typename Function>
  struct my_struct
{
  Function f;

  my_struct(const Function &f) : f(f) {}

  // XXX adding this assignment operator causes an error
  //my_struct &operator=(const my_struct &other)
  //{
  //  f = other.f;
  //  return *this;
  //}
};

template<typename Function>
my_struct<Function> make_struct(const Function &f)
{
  return my_struct<Function>(f);
}

int main()
{
  // create some lambda
  auto lambda = [](int x){return x;};

  // make a struct containing a copy of the lambda
  auto x = make_struct(lambda);

  // try to assign to the struct, which
  // presumably assigns to the enclosed lambda
  x = make_struct(lambda);

  return 0;
}

Добавление закомментированного оператора присваивания приводит к ошибке, как и ожидалось:

$ g++-4.6 -std=c++0x test.cpp
test.cpp: In member function ‘my_struct<Function>& my_struct<Function>::operator=(const my_struct<Function>&) [with Function = main()::<lambda(int)>, my_struct<Function> = my_struct<main()::<lambda(int)> >]’:
test.cpp:34:25:   instantiated from here
test.cpp:13:5: error: use of deleted function ‘main()::<lambda(int)>& main()::<lambda(int)>::operator=(const main()::<lambda(int)>&)’
test.cpp:27:18: error: a lambda closure type has a deleted copy assignment operator

Итак, возможно ли создавать присваиваемые типы с помощью лямбда-переменных-членов? Это кажется разумной вещью, которую хочется попробовать. Рассмотрим, например, объединение лямбды с boost::transform_iterator.

1 Ответ

13 голосов
/ 13 декабря 2011

Ты рядом. Лямбда имеет неявный конструктор копирования и может иметь - в зависимости от захваченных значений - неявный конструктор перемещения. У него есть удаленный оператор присвоения копии.

Другими словами, вы можете создать его, но не можете назначить его. Если вы ищете универсальный объект функции, вы хотите использовать std::function<>. Он эмулирует функции как первоклассные значения.


Обратите внимание, что неизменяемый отличается от назначаемого. Когда лямбда называется изменяемой, это означает, что ее тело вызова функции может изменять члены лямбды (то есть, функция не является const):

int i = 0;

auto okay = [=](int x) mutable { i += x; };
auto error = [=](int x) { i += x; };

Каждый из них является копируемым и не присваиваемым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...