Your problem is two fold. First, you are capturing by reference in a lambda whose lifetime (and the lifetime of its copies) exceeds the current local scope. Don't do that. Only use [&]
if your lambda (and all copies) will not be copied out of the lifetime of the local scope.
The naive answer is to then do a [=]
or [y]
, but you cannot copy a unique pointer.
In C++14, you can do [y=std::move(y)]
which moves the y
into the lambda capture. However, a lambda that has captured a unique_ptr
by-value cannot be copied. And std::function
can only store invokable, destroyable and copyable objects.
A solution to this would be to wait for a move-only function
(which I think is coming down the pipe -- I've seen at least an informal proposal), or roll your own.
template<class Sig>
struct unique_function;
namespace details {
template<class Sig>
struct i_uf_impl;
template<class R, class...Args>
struct i_uf_impl<R(Args...)> {
virtual ~i_uf_impl() {}
virtual R invoke(Args&&...) = 0;
};
template<class Sig, class F>
struct uf_impl;
template<class R, class...Args>
struct uf_impl<R(Args...):i_uf_impl<R(Args...)>{
F f;
virtual R invoke(Args&&...args) override final {
return f(std::forward<Args>(args)...);
}
};
template<class...Args>
struct uf_impl<void(Args...):i_uf_impl<void(Args...)>{
F f;
virtual void invoke(Args&&...args) override final {
f(std::forward<Args>(args)...);
}
};
}
template<class R, class...Args>
struct unique_function<R(Args...)> {
std::unique_ptr<details::i_uf_impl<R(Args...)>> pimpl;
unique_function(unique_function&&)=default;
unique_function& operator=(unique_function&&)=default;
unique_function()=default;
template<class F, class=std::enable_if_t<
!std::is_same<std::decay_t<F>, unique_function>
&& ( std::is_convertible<std::result_of_t< F(Args...) >, R >{}
|| std::is_same< R, void >{} )
>>
unique_function(F&& f):pimpl(
new details::uf_impl<R(Args...), std::decay_t<F>>{std::forward<F>(f)}
) {}
// override deduction helper:
unique_function(R(*pfun)(Args...)):pimpl(
pfun?
new details::uf_impl<R(Args...), R(*)(Args...)>{pfun}
: nullptr
) {}
// null case
unique_function(nullptr_t):unique_function(){}
explicit bool operator() const { return static_cast<bool>(pimpl); }
R operator()(Args...args)const{
return pimpl->invoke( std::forward<Args>(args)... );
}
};
which may or may not work, but should give you the gist.