Jes*_*Jes 5 lambda c++11 std-function
我对std::function在给定的lambda中构造的方式感到有些困惑.这里std::function列出了构造函数.哪一个实际用于捕获一个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
Run Code Online (Sandbox Code Playgroud)
简而言之,标准规定只有可复制的函数对象才能存储在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; }
};
Run Code Online (Sandbox Code Playgroud)
上面是 a 的玩具示例std::function<void()>。
复制的操作存储->clone()在的方法中pimpl。即使您从未调用过它,也必须对其进行编译。
规范的编写者std意识到上述技术,并且知道其局限性,并且希望允许std::function简单地使用它来实现。此外,他们希望对 的简单操作以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)...);
};
}
Run Code Online (Sandbox Code Playgroud)
现在:
std::function<Sig> f = shared_state([future=std::move(fu)]() {...});
Run Code Online (Sandbox Code Playgroud)
将编译并运行。
另一种方法是制作不可复制的std::function并使用它来代替std::function.
最后,当使用 时future, ashared_future是一种可复制future类型,并且可能比使用 a 更便宜shared_state:
std::function<void()> f = [fu=fu.share()]{ /* code */ };
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
417 次 |
| 最近记录: |