- 主题:被 std::function 坑一回
用到回调函数,为了支持虚函数,不用模板类型参数表示回调函数,而用了 std::function 包装。结果用 lambda 表达式传参的时候,有 move 捕获变量就编译失败了。代码类似这样:
void api(std::function<void()>&& callback)
{
callback();
}
void caller()
{
auto ptr = std::make_unique<Foo>();
api([p=std::move(ptr)]() mutable{
p->bar();
});
}
按惯例,错误信息还是一下子难以看懂。最后查来查去搞明白 std::function 要求保存的可调用对象是 copy constructable 的,而加了移动的捕获变量的 lambda 就不满足了。这问题还不好绕过去,这里最后改成 shared_ptr 了。
感觉 C++ 规则多还是一言难尽。惭愧我一开始写这段代码连mutable都不知道加。
--
FROM 120.36.49.*
std::function 我把它当成指针看。。
就好像 shared_ptr<> 一样,你不需要用 && 或者 & 来优化。
【 在 milksea (肥了,又肥了 >>>_<<<) 的大作中提到: 】
: 用到回调函数,为了支持虚函数,不用模板类型参数表示回调函数,而用了 std::function 包装。结果用 lambda 表达式传参的时候,有 move 捕获变量就编译失败了。代码类似这样:
: void api(std::function<void()>&& callback)
: {
: ...................
--
FROM 121.205.116.*
而加了移动的捕获变量的 lambda 就不满足了。
我觉得这句话是不对的.
这里lambda变得不可copyconstructable的原因是你的lambda有一个std::unique_ptr的成员变量.
你move一个int看看,就没有问题.
而且我不认为你加了mutable就可以通过编译.
因为mutable只是去掉了lambda里面unique_ptr前面那个隐式的const qualifier.
struct Foo
{
void bar()
{
}
};
void api(std::function<void()>&& callback)
{
callback();
}
void caller()
{
auto ptr = std::make_unique<Foo>();
api([p=std::move(ptr)]() mutable{
p->bar();
});
}
int main()
{
caller();
return 0;
}
我编译了一下,错误信息显示仍然是调用了unique_ptr的copy ctor,和预期相符.
In file included from /usr/include/c++/10/functional:59,
from main.cpp:1:
...
error
...
...
main.cpp:19:25: note: ‘caller()::<lambda()>::<lambda>(const caller()::<lambda()>&)’ is implicitly deleted because the default definition would be ill-formed:
19 | api([p=std::move(ptr)]() mutable{
| ^
main.cpp:19:25: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Foo; _Dp = std::default_delete<Foo>]’
In file included from /usr/include/c++/10/memory:83,
from main.cpp:2:
/usr/include/c++/10/bits/unique_ptr.h:468:7: note: declared here
468 | unique_ptr(const unique_ptr&) = delete;
| ^~~~~~~~~~
【 在 milksea 的大作中提到: 】
: 用到回调函数,为了支持虚函数,不用模板类型参数表示回调函数,而用了 std::function 包装。结果用 lambda 表达式传参的时候,有 move 捕获变量就编译失败了。代码类似这样:
: void api(std::function<void()>&& callback)
: {
: ...................
--
修改:allegro FROM 73.63.209.*
FROM 73.63.209.*
std::function没必要按引用传,直接传值就行了
--
FROM 171.83.9.*
api([p=std::move(ptr)](){
p->bar();
});
p的类型是auto p = std::move(ptr)的p的类型.
auto的推导规则会忽略&&, p的类型就是ptr的类型.
所以这个lambda有这个成员变量: const std::unique_ptr p;
【 在 allegro 的大作中提到: 】
: 而加了移动的捕获变量的 lambda 就不满足了。
: 我觉得这句话是不对的.
: 这里lambda变得不可copyconstructable的原因是你的lambda有一个std::unique_ptr的成员变量.
: ...................
--
FROM 73.63.209.*
使用folly function. STD function 设计有比较大问题.
【 在 milksea () 的大作中提到: 】
: 用到回调函数,为了支持虚函数,不用模板类型参数表示回调函数,而用了 std::function 包装。结果用 lambda 表达式传参的时候,有 move 捕获变量就编译失败了。代码类似这样:
:
: void api(std::function<void()>&& callback)
: {
--
FROM 45.87.213.*
【 在 allegro 的大作中提到: 】
: api([p=std::move(ptr)](){
: p->bar();
: });
: ...................
“lambda有这个成员变量: const std::unique_ptr p”
你这种阐述方式我倒是第一次见,我一直只是觉得捕捉变量之后只是这个名字能在lambda里面用而已,但是你直接说成lambda的成员变量似乎更加形象。
--
FROM 1.91.32.*
这个不本质
【 在 hgoldfish 的大作中提到: 】
: std::function 我把它当成指针看。。
:
: 就好像 shared_ptr<> 一样,你不需要用 && 或者 & 来优化。
: ...................
--
FROM 120.36.49.*
可是标准大概率不会改了
【 在 Rob 的大作中提到: 】
: 使用folly function. STD function 设计有比较大问题.
:
: 【 在 milksea () 的大作中提到: 】
: ...................
--
FROM 120.36.49.*
嗯,可能我没说清楚。我是说不加mutable还有别的问题,lamda表达式里修改参数需要mutable声明。
我遇到的问题是std::function需要copy ctor,这个没有好解法
【 在 allegro 的大作中提到: 】
: 而加了移动的捕获变量的 lambda 就不满足了。
:
: 我觉得这句话是不对的.
: ...................
--
FROM 120.36.49.*