TestCase2
and TestCase3
can compile normally. However, in TestCase1
I get the following error:
E0312, Custom conversion from "lambda []void ()->void" to
"EventHandler" is not appropriate.
Why am I getting this error? I want to know how to solve it.
#include <functional>
#include <iostream>
class EventHandler
{
std::function<void()> _func;
public:
int id;
static int counter;
EventHandler() : id{ 0 } {}
EventHandler(const std::function<void()>& func) : _func{ func }
{
id = EventHandler::counter;
}
};
int EventHandler::counter = 0;
int main()
{
EventHandler TestCase1 = []() {};
EventHandler TestCase2([]() {});
EventHandler TestCase3 = static_cast<std::function<void()>>([]() {});
}
CodePudding user response:
Why am I getting this error?
The lambda []() {}
is not the same as std::function<void()>
. That means
decltype([]() {}) != std::function<void()>
and it has to be implicitly or explicitly converted.
At the line
EventHandler TestCase1 = []() {};
copy initialization take place, where compiler first has to convert the lambda to a std::function<void()>
and then a EventHandler
object. Compiler can not do double implicit conventions.
Therefore, you need to be explicit here, like in TestCase3
for instance.
I want to know how to solve it.
One way is to provide a templated constructor (if you willing to)
#include <type_traits> // std::is_convertible_v
class EventHandler
{
std::function<void()> _func;
public:
template<typename Func> EventHandler(Func func)
: _func{ func }
{
static_assert(std::is_convertible_v<Func, decltype(_func)>
, "is not valid arg!");
// ....
}
// or in C 20 with <concepts> header
// template<typename Func> EventHandler(Func func)
// requires std::convertible_to<Func, decltype(_func)>
// : _func{ func }
// { ... }
};
Now you can
EventHandler TestCase1 = []() {}; // works
CodePudding user response:
You can't assign a lambda directly to an EventHandler
, there is no such conversion. Instead, you can invoke the EventHandler
's constructor by adding curly braces, which will initialize the std::function
with the lambda.
EventHandler TestCase1 = {[]() {}};
CodePudding user response:
Case 1
Here we consider the statement:
EventHandler TestCase1 = []() {};//this is copy initialization
the above statement uses copy initialization.
And from copy initialization's documentation:
In addition, the implicit conversion in copy-initialization must produce
T
directly from the initializer, while, e.g. direct-initialization expects an implicit conversion from the initializer to an argument ofT
's constructor.
And as EventHandler
can't be directly produced from the initializer lambda on the right hand side, the first case of TestCase1
isn't allowed in accordance wirh the above quoted statement.
Case 2
Here we consider the statement,
EventHandler TestCase2([]() {});//this is direct initialization
the above uses direct initialization and since there is an implicit conversion available(using the converting constructor), this time it is allowed according to the above quoted statement.