gpt4 book ai didi

c++11 - std::function 是如何为 lambda 构造的

转载 作者:行者123 更新时间:2023-12-03 08:27:39 25 4
gpt4 key购买 nike

我有点困惑 std::function在给定的 lambda 处构造。 std::function的构造函数已上市 here .哪个实际上用于捕获 lambda?是吗template< class F > function( F f ); ?看起来我无法构建 std::function使用捕获不可复制构造对象的 lambda。为什么这对于 lambda 捕获是必要的?

// fu is an object of type std::future 
std::function f = [future=std::move(fu)]() {...} // compile error

// foo is an object of type int
std::function f = [foo=std::move(foo)]() {...} // compile ok

最佳答案

简短的回答是标准状态只有可复制的函数对象可以存储在 std::function 中。 .这是令人不满意的:为什么?
std::function是可复制的类型。

该标准规定,在复制时,它也会复制其内容。

“但是”,你说,“我从不复制它。为什么要复制它?” std::function的一个实例记录如何复制其内容,即使它从不这样做。它通常使用一种称为类型删除的技术。

这是一个玩具示例:

struct invoke_later {
struct i_impl {
virtual ~i_impl() {}
virtual void invoke() const = 0;
virtual std::unique_ptr<i_impl> clone() const = 0;
};
template<class T>
struct impl:i_impl {
T t;
~impl() = default;
void invoke() const override {
t();
}
impl(T&& tin):t(std::move(tin)) {}
impl(T const& tin):t(tin) {}
virtual std::unique_ptr<i_impl> clone() const {
return std::make_unique<impl>(t);
};
};
std::unique_ptr<i_impl> pimpl;

template<class T,
// SFINAE suppress using this ctor instead of copy/move ctors:
std::enable_if_t< !std::is_same<std::decay_t<T>, invoke_later>{}, int>* =0
>
invoke_later( T&& t ):
pimpl( std::make_unique<impl<std::decay_t<T>>( std::forward<T>(t) ) )
{}

invoke_later(invoke_later&&)=default;
invoke_later(invoke_later const&o):
pimpl(o.pimpl?o.pimpl->clone():std::unique_ptr<i_impl>{})
{}

~invoke_later() = default;

// assignment goes here

void operator() const {
pimpl->invoke();
}
explicit operator bool() const { return !!pimpl; }
};

以上是 std::function<void()> 的玩具示例.

复制的操作存储在 ->clone() pimpl的方法.即使你从不调用它,它也必须被编译。
std作者知道上述技术并知道其局限性的规范,并希望允许 std::function s 只需使用它即可实现。此外,他们希望对 std::function 进行简单的操作。以可预测的方式行事:对于不可复制的内容,应该复制 std::function做?

请注意,您可以通过将状态包装在 shared_ptr 中来解决此问题。 .然后复制您的 std::function将简单地存储对您的状态的共享引用,而不是副本。
template<class F>
auto shared_state( F&& f ) {
return [pf = std::make_shared<std::decay_t<F>>(std::forward<F>(f))]
(auto&&... args)->decltype(auto) {
return (*pf)(decltype(args)(args)...);
};
}

现在:
std::function<Sig> f = shared_state([future=std::move(fu)]() {...});

将编译和工作。

另一种方法是制作不可复制的 std::function并使用它代替 std::function .

最后,与 future 合作, shared_future是可复制的 future类型,可能比做 shared_state 便宜:
std::function<void()> f = [fu=fu.share()]{ /* code */ };

关于c++11 - std::function 是如何为 lambda 构造的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36984904/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com