关于 "lambda []void ()->void" 的自定义转换的问题
Question about custom conversion of "lambda []void ()->void"
TestCase2
和TestCase3
可以正常编译。但是,在 TestCase1
中出现以下错误:
E0312, Custom conversion from "lambda []void ()->void" to
"EventHandler" is not appropriate.
为什么会出现此错误?我想知道怎么解决。
#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?
lambda []() {}
与 std::function<void()>
不同。也就是说
decltype([]() {}) != std::function<void()>
并且必须隐式或显式转换
行
EventHandler TestCase1 = []() {};
copy initialization take place,其中编译器首先必须将 lambda 转换为 std::function<void()>
,然后是 EventHandler
对象。编译器不能执行双重隐式约定。
因此,您需要在此处明确说明,例如 TestCase3
。
I want to know how to solve it.
一种方法是提供模板化构造函数(如果您愿意)
#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 }
// { ... }
};
现在你可以
EventHandler TestCase1 = []() {}; // works
案例一
这里我们考虑语句:
EventHandler TestCase1 = []() {};//this is copy initialization
以上语句使用了复制初始化
并且来自 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 of T
's constructor.
并且由于 EventHandler
不能直接从右侧的初始化程序 lambda 生成,因此根据上面引用的声明,TestCase1
的第一种情况是不允许的。
案例二
这里我们考虑语句,
EventHandler TestCase2([]() {});//this is direct initialization
上面使用的是直接初始化,由于有隐式转换可用(使用转换构造函数),这次按照上面引用的说法是允许的
TestCase2
和TestCase3
可以正常编译。但是,在 TestCase1
中出现以下错误:
E0312, Custom conversion from "lambda []void ()->void" to
"EventHandler" is not appropriate.
为什么会出现此错误?我想知道怎么解决。
#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?
lambda []() {}
与 std::function<void()>
不同。也就是说
decltype([]() {}) != std::function<void()>
并且必须隐式或显式转换
行
EventHandler TestCase1 = []() {};
copy initialization take place,其中编译器首先必须将 lambda 转换为 std::function<void()>
,然后是 EventHandler
对象。编译器不能执行双重隐式约定。
因此,您需要在此处明确说明,例如 TestCase3
。
I want to know how to solve it.
一种方法是提供模板化构造函数(如果您愿意)
#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 }
// { ... }
};
现在你可以
EventHandler TestCase1 = []() {}; // works
案例一
这里我们考虑语句:
EventHandler TestCase1 = []() {};//this is copy initialization
以上语句使用了复制初始化
并且来自 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.
并且由于 EventHandler
不能直接从右侧的初始化程序 lambda 生成,因此根据上面引用的声明,TestCase1
的第一种情况是不允许的。
案例二
这里我们考虑语句,
EventHandler TestCase2([]() {});//this is direct initialization
上面使用的是直接初始化,由于有隐式转换可用(使用转换构造函数),这次按照上面引用的说法是允许的