ここで何かが足りないと思います。
静的関数?
関数を静的に宣言すると、そのコンパイル単位で「非表示」になります。
名前空間スコープ (3.3.6) を持つ名前は、
— 明示的に static と宣言された変数、関数、または関数テンプレート。
3.5/3 - C++14 (n3797)
名前に内部リンケージがある場合、それが示すエンティティは、同じ翻訳単位内の他のスコープからの名前で参照できます。
3.5/2 - C++14 (n3797)
この静的関数をヘッダーで宣言すると、このヘッダーを含むすべてのコンパイル ユニットに独自の関数のコピーが含まれます。
問題は、その関数内に静的変数がある場合、このヘッダーを含む各コンパイル単位にも独自の個人的なバージョンがあることです。
インライン関数?
インラインで宣言すると、インライン化の候補になります (コンパイラがインライン化するかどうかにかかわらず、キーワード inline が存在するか存在しないかという事実を無視する場合があるため、C++ では最近ではあまり意味がありません)。
インライン指定子を使用した関数宣言 (8.3.5、9.3、11.3) は、インライン関数を宣言します。インライン指定子は、呼び出し時点での関数本体のインライン置換が通常の関数呼び出しメカニズムよりも優先されることを実装に示します。呼び出し時にこのインライン置換を実行する実装は必要ありません。ただし、このインライン置換が省略された場合でも、7.1.2 で定義されたインライン関数の他の規則は引き続き尊重されます。
7.1.2/2 - C++14 (n3797)
ヘッダーでは、興味深い副作用があります。インライン化された関数は同じモジュールで複数回定義でき、リンカーは単に「それら」を 1 つに結合します (コンパイラーの理由でインライン化されていない場合)。
内部で宣言された静的変数の場合、標準では、そのうちの1つだけが明確に示されています。
extern インライン関数の静的ローカル変数は、常に同じオブジェクトを参照します。
7.1.2/4 - C++98/C++14 (n3797)
(関数はデフォルトで extern であるため、関数を static として明示的にマークしない限り、これはその関数に適用されます)
これには、欠陥のない「静的」(つまり、ヘッダーで定義できる)という利点があります(インライン化されていない場合、最大で 1 回存在します)。
静的ローカル変数?
静的ローカル変数にはリンケージがありません (スコープ外の名前で参照することはできません) が、静的な保存期間があります (つまり、グローバルですが、その構築と破棄は特定の規則に従います)。
静的 + インライン?
インラインと静的を混在させると、説明した結果が得られます(関数がインライン化されていても、内部の静的変数はインライン化されず、静的関数の定義を含むコンパイル単位と同じ数の静的変数で終了します) )。
著者の追加の質問への回答
質問を書いたので、Visual Studio 2008 で試してみました。VS が標準に準拠して動作するようにするすべてのオプションをオンにしようとしましたが、一部を見逃している可能性があります。結果は次のとおりです。
関数が単に「インライン」である場合、静的変数のコピーは 1 つだけです。
関数が「静的インライン」の場合、翻訳単位と同じ数のコピーがあります。
本当の問題は、物事がこのように想定されているのか、それともこれが Microsoft C++ コンパイラの特異性なのかということです。
だから私はあなたがそのようなものを持っていると思います:
void doSomething()
{
static int value ;
}
関数内の static 変数は、簡単に言えば、関数のスコープ以外には隠されているグローバル変数であり、内部で宣言されている関数だけがアクセスできることを意味します。
関数をインライン化しても何も変わりません:
inline void doSomething()
{
static int value ;
}
非表示のグローバル変数は 1 つだけです。コンパイラがコードをインライン化しようとしても、グローバル隠し変数が 1 つしかないという事実は変わりません。
ここで、関数が静的に宣言されている場合:
static void doSomething()
{
static int value ;
}
次に、コンパイル単位ごとに「プライベート」です。つまり、静的関数が宣言されているヘッダーを含むすべての CPP ファイルには、グローバル隠し変数の独自のプライベート コピーを含む、関数の独自のプライベート コピーがあるため、変数はヘッダーを含むコンパイル単位があります。
「静的」変数を内部に持つ「静的」関数に「インライン」を追加します。
inline static void doSomething()
{
static int value ;
}
内部の静的変数に関する限り、この「インライン」キーワードを追加しない場合と同じ結果になります。
したがって、VC++ の動作は正しく、「インライン」と「静的」の本当の意味を誤解しています。