3

Following code doesn't compile. Because pt has type of const std::packaged_task<void()>> and operator() is not const.

auto packagedTask = std::packaged_task<void()>>([]{});
auto future = packagedTask.get_future();
auto function = [pt = std::move(packagedTask)]{ (*pt)(); });

Here is workaround:

auto packagedTask = std::make_shared<std::packaged_task<void()>>([]{});
auto future = packagedTask->get_future();
auto function = [pt = std::move(packagedTask)]{ (*pt)(); });

Why local variables in the lambda object are const? I want to make first code work without overheads to workarounds. What is best practice to solve the issue?

Viktor
  • 1,004
  • 1
  • 10
  • 16

1 Answers1

6

Unless the lambda is marked as mutable, the generated lambda::operator() will be qualified as const. Marking your lambda as mutable will prevent this behavior:

auto function = [pt = std::move(packagedTask)]() mutable { (*pt)(); });

Why local variables in the lambda object are const?

Local variables in closures generated by lambda expressions are not const. It's the generated lambda::operator() that's qualified as const. A better question might be "Why is a lambda's operator() implicitly const?

It's because const is a better default than mutable. Mutability introduces complexity. Immutability makes code easier to reason about.

const should be the language-wide default, but that's impossible to change due to retrocompatibility. Since lambdas were a brand new feature, the committee decided to go with const by-default and opt-in mutability.

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • Thanks! I need to store lambda objects in `std::function` but lambda with `std::package_task` cannot be assigned: `std::function f = [pt = std::move(packagedTask)]() mutable { pt(); };` – Viktor Jul 14 '17 at 12:35
  • 1
    `std::function` does not support move-only callables: https://stackoverflow.com/questions/25330716/move-only-version-of-stdfunction – Vittorio Romeo Jul 14 '17 at 12:48