Reputation: 567
I have a class in which I deleted the copy assignment operator and copy constructor, leaving only a move assignment operator and move constructor. For example:
struct Number {
public:
int *pNum;
Number &operator=(const Number &rhs) = delete;
Number(const Number &rhs) = delete;
Number &operator=(Number &&rhs) {
if (&rhs == this) {
return *this;
}
pNum = rhs.pNum;
rhs.pNum = nullptr;
return *this;
}
Number() = default;
Number(Number &&rhs) {
*this = std::move(rhs);
}
~Number() {
delete pNum;
}
};
Now, I want to use std::move
to capture this class into a lambda. For example:
int main() {
std::function<int(int)> add;
int a = 3;
{
Number n{};
n.pNum = new int;
*n.pNum = 5;
add = [&, capA{std::move(n)}](int) mutable -> int {
int b = *capA.pNum; // 5
return a + b; // 8
};
}
std::cout << add(3);
}
However, it seems that n
would be const
so that c++ would try to use the deleted copy constructor. How would I fix this? (REPL: https://repl.it/@25GrantY/WeirdLambda)
Upvotes: 1
Views: 971
Reputation: 164
the problem here is coming from std::function. This class must satisfy CopyConstructible and CopyAssignable requirements, according to documentation. https://en.cppreference.com/w/cpp/utility/functional/function
std::function satisfies the requirements of CopyConstructible and CopyAssignable.
When you attempt to initialize std::function with a lambda that captured move-only type by value, such assignment (if successful) would violate the both of the requirements above.
This is why compilation fails with an error.
How to fix this?
Either do not use std::function, or make your lambda copyable.
You can use std::shared_ptr as a copyable wrapper for move-only type.
auto shared_number = std::make_shared<Number>{};
Now, you can pass shared_number to lambda, and assign to std::function.
Upvotes: 5
Reputation: 75727
The problem isn't with the lambda. E.g. this works:
auto l = [&, capA{std::move(n)}](int) mutable -> int {
int b = *capA.pNum; // 5
return a + b; // 8
};
The problem is with std::function
and this lambda. Because you capture a non-copyable object then the lambda is non-copyable. std::function
requires its stored object to be copyable so that's why it doesn't work.
You can read more here: Move-only version of std::function
Upvotes: 7