あなたは
auto unevaluted_x = []() { return foo(); };
...
auto x = unevaluted_x();
にあなたが(あなたがunevaluated_x
を呼び出すとき)の値を取得したいたびに書き込み、それは計算リソースを浪費し、計算しています。したがって、この過度の作業を取り除くために、ラムダが既に呼び出されているかどうかを追跡することをお勧めします(おそらく他のスレッドやコードベース内の非常に異なる場所)。そうするために、我々は、ラムダの周りにいくつかのラッパーが必要になります。
template<typename Callable, typename Return>
class memoized_nullary {
public:
memoized_nullary(Callable f) : function(f) {}
Return operator()() {
if (calculated) {
return result;
}
calculated = true;
return result = function();
}
private:
bool calculated = false;
Return result;
Callable function;
};
は、このコードは単なる一例であり、スレッドセーフではありませんのでご注意ください。
しかし、その代わりに車輪の再発明の、あなただけのstd::shared_future
を使用することができます。これは、書き込みに少ないコードを必要とし、他のいくつかの機能をサポートしてい
auto x = std::async(std::launch::deferred, []() { return foo(); }).share();
(のように、値が既に計算されているかどうかをチェックし、スレッドの安全性、等)。標準で次のテキストがあります
[futures.asyncは、(3.2)]:launch::deferred
は、ポリシーに設定されている
場合は、店舗共有状態でDECAY_COPY(std::forward<F>(f))
とDECAY_COPY(std::forward<Args>(args))...
。 f
とargs
のこれらのコピーは、 という遅延機能を構成します。遅延関数の呼び出しは、g
がDECAY_COPY(std::forward<F>(f))
およびxyz
の格納値である場合、DECAY_COPY(std::forward<Args>(args))....
の格納されたコピーである です。返される値は、共有状態の結果として に格納されます。遅延された 関数の実行から伝播された例外は、例外的な結果として共有状態に格納されます。機能が完了するまで、共有状態は になりません。この共有状態を参照する非同期戻りオブジェクトの非タイミング待ち関数(30.6.4) への最初の呼び出しは、待機ファンクションを呼び出した遅延ファンクション を呼び出します。 INVOKE(std::move(g),std::move(xyz))
の評価が開始されると、その機能はもはや延期されているとはみなされません。 [注:ポリシー値がlaunch::async | launch::deferred
の場合など、このポリシーが他のポリシーとともに指定されている場合は、 が有効に悪用されることがない場合、実装では呼び出しまたはポリシーの選択を延期する必要があります。 -end note]
したがって、計算が必要になる前に呼び出されることはありません。
未来は、(おそらく非同期の)プロセスの結果を待つためのものです。彼らは一度使用してかなりヘビーなです。同じスレッドで怠惰な評価を探しているのなら、おそらく必要なものではないでしょう。 boost.outcomeという名前のライブラリが開発されています。本質的に軽量の先物(クロススレッド作業用に設計されていない)です。 遅延関数を繰り返し呼び出す場合は、おそらく関数オブジェクトまたはラムダが適しています。あなたはまた、boost.hanaまたは同様のものを見たいかもしれません。 –