Die kurze Antwort ist, dass die Standardzustände nur kopierbare Funktionsobjekte in einer std::function
gespeichert werden können. Das ist unbefriedigend: warum?
std::function
ist ein kopierbarer Typ.
Der Standard besagt, dass beim Kopieren auch der Inhalt kopiert wird.
"Aber", sagst du, "ich kopiere es nie. Warum sollte es kopiert werden?" Eine Instanz std::function
Datensätze wie seinen Inhalt zu kopieren, auch wenn es nie tut. Es verwendet typischerweise eine Technik, die als Typlöschung bekannt ist.
ist hier ein Spielzeug Beispiel:
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; }
};
die oben ist ein Spielzeug Beispiel eines std::function<void()>
.
Der Kopiervorgang ist gespeichert in der ->clone()
Methode der pimpl
. Es muss kompiliert werden, auch wenn Sie es nie nennen.
Die Autoren der std
Spezifikation, wo bewusst, die oben genannten Technik, und wusste seine Grenzen, und wollte std::function
s einfach implementiert werden, damit es implementiert werden. Darüber hinaus wollten sie einfache Operationen auf der std::function
auf vorhersehbare Weise verhalten: mit nicht kopierbaren Inhalten, was sollte das Kopieren std::function
tun?
Hinweis: Sie können dieses Problem umgehen, indem Sie Ihren Status in eine shared_ptr
umhüllen. Copys von std::function
speichern einfach gemeinsame Referenzen anstelle von Kopien auf Ihren Status.
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)...);
};
}
jetzt:
std::function<Sig> f = shared_state([future=std::move(fu)]() {...});
kompilieren und zu arbeiten.
Ein alternativer Ansatz besteht darin, einen nicht kopierbaren std::function
zu erstellen und diesen anstelle von std::function
zu verwenden.
Schließlich WHE mit future
arbeiten, ein shared_future
ist ein kopierbar future
Typ und kann billiger sein als eine shared_state
tun:
std::function<void()> f = [fu=fu.share()]{ /* code */ };
ähnliche Frage: http://stackoverflow.com/questions/25421346/how- to-create-a-stdfunction-from-a-move-capturen-lambda-expression – marcinj