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()>>([]() {});
}
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