プログラムが正確に1回実行する必要がある大きな(またはそうでない)コードを記述する必要がある人のために、小さな既製のソリューションを提示したいと思います。 さらに、(合理的なC ++構文規則の制限内で)どこにでも配置する必要がある場合があります。 この必要性がプロジェクト全体で数回より頻繁に発生する場合は、少なくとも多少は作業を行い、可能であればあまり松葉杖ではない解決策があるとよいでしょう。
まっすぐに
長い間考えずに、標準C ++ 11以降で動作するコードをすぐに投稿します。
#include <iostream> #define DO_ONCE(...) { static bool _do_once_ = ([&](){ __VA_ARGS__ }(), true); (void)_do_once_; } void Foo(int val) { using namespace std; // _do_once_ DO_ONCE static unsigned int _do_once_ = 1; DO_ONCE ( cout << "[First call of 'Foo' function]" << endl; ) cout << "Calls: " << _do_once_++ << ", value: " << val << endl; } int main(int argc, char** argv) { using namespace std; for (auto val : {1, 2, 3}) { Foo(val); DO_ONCE ( Foo(val); ) } system("pause > nul"); return 0; } /* : [First call of 'Foo' function] Calls: 1, value: 1 Calls: 2, value: 1 Calls: 3, value: 2 Calls: 4, value: 3 /*
必要なすべての作業を行う最も重要なコードを検討してください。
#define DO_ONCE(...) { static bool _do_once_ = ([&](){__VA_ARGS__}(), true); (void)_do_once_; }
あまり明確で見栄えがよくないので、もう少し書きます。
#define DO_ONCE(...) \ { \ static bool _do_once_ = ([&] ( ) { __VA_ARGS__ } ( ), true); \ (void)_do_once_; \ }
これは次のように機能します-コードブロックで、ブール型のローカル静的変数が作成されます。これは、「カンマ」演算子を使用して、2段階で初期化されます。
1.括弧演算子を使用して、ラムダが呼び出されます。
[&] ( ) { __VA_ARGS__ }
これは、スコープ内にあるすべてを参照によってキャプチャし、ユーザーが__VA_ARGS__に「パック」された引数を介してDO_ONCEマクロに渡した式を実行し
ます 。
定義済みマクロ
__VA_ARGS__を使用すると、コンマ(プリプロセッサが解析段階で引数の区切り文字と見なす)が含まれている場合でも、ブロック内のすべてのコードを保存できます。
2.変数_do_once_はtrueに設定されます(割り当てられた値と変数の型自体は役割を果たしません。プログラムで占有されているサイズはカウントしません)。 エントリ「(void)_do_once_;」 未使用の変数に関する警告を避けるために必要です。
この時点で、変数の初期化が完了し、このコードを超えて実行されることはありません。これは達成する必要があったものです。
アプローチの短所:-C ++ 11標準が必要、
-DO_ONCEブロックごとに1つの変数を作成する必要があります。
長所:-読みやすさ、シンプルな構文。
-ブロック内のステートメントの数とタイプに制限はありません(サイクルがDO_ONCEブロックボディの外側にある場合はbreakを入力し、DO_ONCEがスイッチ内にある場合はcaseラベルを続行しないでください)。
-DO_ONCE呼び出しのスコープで使用可能な変数と関数を、引数として渡す追加コストなしで機能する機能。
-変数_do_once_をオーバーライドするエラーが発生するリスクはありません。 ブロックの本体では、外側のスコープからこの名前を単純に置き換えます。
使用された文献:
»
ラムダ式»
可変引数リストを持つマクロ