inline指定子
関数 decl-specifier-seq で使用される inline 指定子は、関数をインライン関数として宣言します。
クラス/構造体/共用体の定義内に完全に定義された関数は、それがメンバー関数であろうと非メンバー friend 関数であろうと、暗黙的にインライン関数となります (ただし、名前付きモジュールにアタッチされている場合を除く)(C++20 以降)。
|
最初の宣言で constexpr または consteval(C++20 以降) と宣言された関数は、暗黙的にインライン関数となります。 削除された関数は暗黙的にインライン関数となります。その (削除された) 定義は複数の翻訳単位に現れることがあります。 |
(C++11以降) |
|
静的記憶域期間を持つ変数 (静的クラスメンバーまたは名前空間スコープ変数) の decl-specifier-seq で使用される inline 指定子は、その変数をインライン変数として宣言します。 最初の宣言で constexpr と宣言された静的データメンバーは、暗黙的にインライン変数となります。 |
(C++17以降) |
目次 |
[編集] 説明
インライン関数またはインライン変数(C++17 以降)は以下のプロパティを持ちます。
- インライン関数または変数(C++17 以降)の定義は、それがアクセスされる翻訳単位内で到達可能でなければなりません (アクセス時点より前である必要はありません)。
- 外部リンケージを持つインライン関数または変数(C++17 以降) (例: static と宣言されていないもの) は、以下の追加のプロパティを持ちます。
- プログラム中にインライン関数または変数(C++17 以降)の複数の定義が存在しても構いません。ただし、各定義が異なる翻訳単位に現れ、かつ (非静的インライン関数と変数(C++17 以降)の場合) すべての定義が同一である必要があります。例えば、インライン関数またはインライン変数(C++17 以降)は、複数のソースファイルでインクルードされるヘッダーファイルに定義されることがあります。
- それはすべての翻訳単位で inline と宣言されなければなりません。
- それはすべての翻訳単位で同じアドレスを持ちます。
インライン関数では、
- すべての関数定義における関数ローカルな静的オブジェクトは、すべての翻訳単位で共有されます (それらはすべて、1つの翻訳単位で定義された同じオブジェクトを参照します)。
- すべての関数定義で定義された型も、すべての翻訳単位で同じです。
|
名前空間スコープのインライン const 変数は、デフォルトで外部リンケージを持ちます (非インラインかつ非 volatile な const 修飾された変数とは異なります)。 |
(C++17以降) |
inline キーワードの本来の意図は、関数呼び出しではなく関数のインライン展開が推奨されることをオプティマイザに示すインジケーターとして機能することでした。つまり、関数呼び出しCPU命令を実行して関数本体に制御を転送する代わりに、関数本体のコピーが呼び出しを生成せずに実行されます。これにより、関数呼び出しによって生じるオーバーヘッド (引数の渡しと結果の取得) を回避できますが、関数本体のコードを複数回繰り返す必要があるため、実行ファイルが大きくなる可能性があります。
インライン展開は標準セマンティクスでは観測できないため、コンパイラは inline とマークされていない任意の関数に対してインライン展開を使用することができ、inline とマークされた任意の関数に対して関数呼び出しを生成することもできます。これらの最適化の選択は、上記の複数の定義と共有静的に関するルールを変更しません。
|
C++98 以降、関数に対する inline キーワードの意味が「インライン化が推奨される」ではなく「複数の定義が許可される」となったため、その意味が変数にも拡張されました。 |
(C++17以降) |
[編集] 注記
外部リンケージを持つインライン関数または変数(C++17 以降)が異なる翻訳単位で異なる定義を持つ場合、プログラムは診断不要で不正形式となります。
inline 指定子は、ブロックスコープ (別の関数の内部) での関数または変数(C++17 以降)宣言には使用できません。
inline 指定子は、翻訳単位内で既に非インラインとして定義された関数または変数(C++17 以降)を再宣言することはできません。
暗黙的に生成されるメンバー関数と、最初の宣言で defaulted と宣言された任意のメンバー関数は、クラス定義内で定義された他の関数と同様にインラインです。
インライン関数が異なる翻訳単位で宣言される場合、各翻訳単位の終わりで、蓄積されたデフォルト引数のセットは同じでなければなりません。
C では、インライン関数はすべての翻訳単位で inline と宣言されている必要はありません (多くとも1つは非 inline または extern inline であることができます)。関数定義は同一である必要はありません (ただし、呼び出された定義にプログラムの動作が依存する場合、その動作は未指定です)。また、同じ関数の異なる定義間では関数ローカルな静的変数は別個です。
|
インライン静的メンバーに関する追加のルールについては、静的データメンバーを参照してください。 インライン変数は、C++ コードをヘッダーオンリーライブラリとしてパッケージ化する際の主な障害を排除します。 |
(C++17以降) |
| 機能テストマクロ | 値 | 規格 | 機能 |
|---|---|---|---|
__cpp_inline_variables |
201606L |
(C++17) | インライン変数 |
[編集] キーワード
[編集] 例
ヘッダー "example.h"
#ifndef EXAMPLE_H #define EXAMPLE_H #include <atomic> // function included in multiple source files must be inline inline int sum(int a, int b) { return a + b; } // variable with external linkage included in multiple source files must be inline inline std::atomic<int> counter(0); #endif
ソースファイル #1
#include "example.h" int a() { ++counter; return sum(1, 2); }
ソースファイル #2
#include "example.h" int b() { ++counter; return sum(3, 4); }
[編集] 欠陥レポート
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| CWG 281 | C++98 | friend 関数宣言は inline 指定子を使用できる たとえフレンドされた関数がインライン関数でなくても |
そのような使用を禁止する |
| CWG 317 | C++98 | 関数はインラインで宣言できる 宣言前に同じ翻訳単位で非インライン定義がある場合でも |
この場合、プログラムは 不正となる |
| CWG 765 | C++98 | インライン関数で定義された型は 異なる翻訳単位で異なる可能性がある |
そのような型はすべて 翻訳単位で同じである |
| CWG 1823 | C++98 | インラインのすべての定義における文字列リテラルは すべての翻訳単位で共有される |
この要件は 整合性と実装のために削除された |
| CWG 2531 | C++17 | 静的データメンバーは暗黙的にインラインにできる 最初の宣言で constexpr と宣言されていない場合でも |
この場合は暗黙的に インラインではない |
[編集] 関連項目
| inline のC ドキュメント
|