I have recently upgraded to Visual Studio 2022 and am having problems with assignment operators and std::function.
We have a class which allows us to call a function when it is destroyed. Note that I don't want to use a finally block to solve this.
See the code below:
class CFinallyCallFunction
{
public:
CFinallyCallFunction(const std::function<void(void)>& finallyFn) : m_finallyFn(finallyFn) {}
~CFinallyCallFunction() { if (m_finallyFn != nullptr) m_finallyFn(); }
void operator=(const std::function<void(void)>& finallyFn) { m_finallyFn = finallyFn; }
protected:
std::function<void(void)> m_finallyFn;
};
void Test()
{
CFinallyCallFunction fn1([] {}); // Compiles
CFinallyCallFunction fn2 = [] {}; // Error
}
The error I'm getting is this:
Error C2440 'initializing': cannot convert from 'Test::<lambda_2>' to 'CFinallyCallFunction'
The problem is that the definition
CFinallyCallFunction fn2 = [] {};
is using copy-initialization, not assignment.
And because there's no direct conversion possible for a lambda to a CFinallyCallFunction
object, the initialization fails.
As a possible solution you can add a templated constructor which can take any argument and use it to initialize the member variable:
template<typename F>
CFinallyCallFunction(F&& finallyFn) : m_finallyFn(finallyFn) {}
Now you can use your class with any kind of callable type.
Also please note that your assignment operator isn't typical. To allow for chained assignments it needs to return a reference to this
.