簡潔な答えは、標準状態でコピー可能な関数オブジェクトのみを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()>
のおもちゃの一例です。
pimpl
の->clone()
の方法では、コピーの操作はであり、コピーはです。と決して呼ばれない場合でも、をコンパイルする必要があります。
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)...);
};
}
:
std::function<Sig> f = shared_state([future=std::move(fu)]() {...});
をコンパイルして動作します。
代わりの方法は、コピー不可能なものをstd::function
にして、それをstd::function
の代わりに使用することです。
最後に、future
で作業WHE、shared_future
はコピー可能future
タイプで、shared_state
を行うよりも安くなることがあります。
std::function<void()> f = [fu=fu.share()]{ /* code */ };
同様の質問:http://stackoverflow.com/questions/25421346/how-移動後のキャプチャラムダ式を作成するには – marcinj