Reputation: 5039
Consider the following code:
#include <iostream>
#include <thread>
int main() {
std::thread t;
const auto l = [x = std::move(t)]{};
decltype(l) m = std::move(l);
}
This code doesn't compile with the following messages:
prog.cc: In function 'int main()': prog.cc:7:32: error: use of deleted function 'main()::<lambda()>::<lambda>(const main()::<lambda()>&)' 7 | decltype(l) m = std::move(l); | ^ prog.cc:6:37: note: 'main()::<lambda()>::<lambda>(const main()::<lambda()>&)' is implicitly deleted because the default definition would be ill-formed: 6 | const auto l = [x = std::move(t)]{}; | ^ prog.cc:6:37: error: use of deleted function 'std::thread::thread(const std::thread&)' In file included from prog.cc:2: /opt/wandbox/gcc-head/include/c++/10.0.1/thread:154:5: note: declared here 154 | thread(const thread&) = delete; | ^~~~~~
Is there a way to make lambda non-copyable or non-movable without explicit capturing an any non-copyable variable (i.e. leaving []
empty)?
Upvotes: 3
Views: 306
Reputation: 170104
You can write a simple enveloping aggregate that will prevent the move and copy.
struct NoCopyMove {
NoCopyMove(NoCopyMove const&) = delete;
NoCopyMove(NoCopyMove&&) = delete;
void operator=(NoCopyMove const&) = delete;
void operator=(NoCopyMove&&) = delete;
};
template<class Functor>
struct Fixed : Functor, NoCopyMove {
using Functor::operator();
};
template<typename F>
Fixed (F&&) -> Fixed<std::decay_t<F>>;
To be used like this
const auto l = Fixed{[]{}};
NoCopyMove
is a simple mixin that disables copying and moving. Writing it this way allows us to keep the specializations of Fixed
as simple aggregates.
All Fixed
does is inherit/initialize as base (with guaranteed copy elision when possible) the functor it's being given as an argument. And then expose its operator()
.
Since there are no members involved (other then maybe in Functor
), and since a lambda cannot possibly inherit from our custom NoCopyMove
class, the empty base optimization kicks in for stateless lambdas. So objects are not expected to be any larger than the lambda you initialize them with.
Upvotes: 7