inline
は、 here を読んだため廃止されたと信じていました。
関数を
inline
として指定する方法に関係なく、コンパイラーは無視することが許可されています。コンパイラーは、inline
として指定された関数を呼び出す場所の一部、すべて、またはまったくインライン展開しない場合があります。
ただし、 Angew は、私が理解していないことを理解しているようです。 この質問 では、inline
がまだ有用かどうかについて、彼と私はかなりやり取りします。
この質問はではなくに関する質問です。
inline
の歴史的な使用、またはinline
を使用して、コンパイラにinline
関数のヒントを与えることができます: 関数/メソッドのキーワード 'inline' .inline
関数コードを強制する: force inline function in other translation unitコンパイラは意のままにinline
できるので、そこでinline
は役に立たないことに注意してください:どこでinline
を使用して強制することができますか、示唆されません、コンパイルされたコードの変更?
できる限り最善の方法で「秘密の理解」を説明しようとします。
ここには、2つのまったく異なる概念があります。 1つは、呼び出しサイトで関数本体を直接繰り返すことにより、関数呼び出しを置き換えるコンパイラーの機能です。もう1つは、複数の変換単位(=複数の.cpp
ファイル)で関数を定義する可能性です。
最初のものは関数のインライン化と呼ばれます。 2番目はinline
キーワードの目的です。 歴史的にinline
キーワードは、inline
とマークされた関数をインライン化する必要があるというコンパイラーへの強い提案でもありました。コンパイラの最適化が向上するにつれて、この機能は廃止され、関数をインライン化するための提案としてinline
を使用することは実際に廃止されました。コンパイラは、それをより適切な最適化であると判断した場合、喜んで無視し、他の何かを完全にインライン化します。
明示的なinline
– inlining関係を扱ったことを願っています。現在のコードには何もありません。
inline
キーワードの実際の目的は何ですか?簡単です:inline
とマークされた関数は、One Definition Rule(ODR)に違反することなく、複数の翻訳単位で定義できます。次の2つのファイルを想像してください。
file1.cpp
int f() { return 42; }
int main()
{ return f(); }
file2.cpp
int f() { return 42; }
このコマンド:
> gcc file1.cpp file2.cpp
シンボルf
が2回定義されていると文句を言って、リンカーエラーを生成します。
ただし、関数をinline
キーワードでマークすると、コンパイラとリンカーに具体的に次のように伝えます。「この関数の複数の同一の定義がnotを実行するとエラーが発生することを確認します!」
したがって、次のように機能します。
file1.cpp
inline int f() { return 42; }
int main()
{ return f(); }
file2.cpp
inline int f() { return 42; }
これらの2つのファイルを一緒にコンパイルおよびリンクしても、リンカーエラーは発生しません。
もちろん、f
の定義は、必ずしもファイル内にある必要はありません。代わりに#include
dヘッダーファイルから取得できます。
f.hpp
inline int f() { return 42; }
file1.cpp
#include "f.hpp"
int main()
{ return f(); }
file2.cpp
#include "f.hpp"
基本的に、関数定義をヘッダーファイルに書き込むには、inline
としてマークする必要があります。そうしないと、複数の定義エラーが発生します。
パズルの最後のピースは次のとおりです。インライン化とは何の関係もないのに、キーワードが実際にinline
と綴られるのはなぜですか?理由は簡単です。関数をインライン化する(つまり、呼び出しサイトで本体を繰り返して呼び出しを置き換える)ために、コンパイラは最初にhaveである必要があります。
C++は、compilerが現在生成しているもの以外のオブジェクトファイルにアクセスできない、別個のコンパイルモデルに従います。したがって、関数をインライン化するには、その定義が現在の翻訳単位の一部である必要があります。複数の翻訳単位でインライン化できるようにしたい場合は、すべての翻訳単位で定義する必要があります。通常、これは多重定義エラーにつながります。したがって、関数をヘッダーに配置し、その定義をどこでも#include
どこでもインライン化できるようにする場合、複数の定義エラーを防ぐためにinline
としてマークする必要があります。
今日でも、コンパイラーはすべての関数が適切であるとインライン化されますが、その関数の定義にアクセスできる必要があります。したがって、「これをインライン化してください」というヒントとしてinline
キーワードは必要ありませんが、enableを選択した場合にインライン化を行うためにコンパイラを使用する必要があることがあります。そうする。これがないと、翻訳単位に定義を取得できない可能性があり、定義がないと、コンパイラは単に関数をインライン化できません。
コンパイラーはできません。リンカーはできます。最新の最適化手法には、リンク時コード生成(プログラム全体の最適化)が含まれます。この場合、最適化は、実際のリンクの前に、リンクプロセスの一部としてすべてのオブジェクトファイルに対して実行されます。このステップでは、すべての関数定義がもちろん利用可能であり、プログラム内のどこでも単一のinline
キーワードを使用しなくてもインライン化が完全に可能です。しかし、この最適化は、特に大規模なプロジェクトの場合、一般的にビルド時間のコストがかかります。これを念頭に置いて、インライン化をLTCGのみに依存することは最良の選択肢ではないかもしれません。
完全を期すために:最初の部分で少しごまかしました。 ODRプロパティは、実際にはinline
キーワードのプロパティではなく、インライン関数(言語の用語)のプロパティです。インライン関数のルールは次のとおりです。
inline
キーワードは、関数をインライン関数に変換します。関数をインラインとしてマークする別の方法は、クラス定義で関数を直接宣言するだけでなく定義することです。このような関数は、inline
キーワードがなくても自動的にインライン化されます。
inline
は、あなたが述べた理由から、現在はほとんど外部リンケージ指定子にすぎません。
そう、それは確かに用途がありますが、実際に関数をインライン化するのとは異なります。複数の定義エラーを取得する代わりに、コンパイル単位間で同じメソッドを複数回定義し、それらを適切にリンクすることができます。
//header.h
inline void foo() {}
void goo() {}
//cpp1.cpp
#include "header.h"
//cpp2.cpp
#include "header.h"
// foo is okay, goo breaks the one definition rule (ODR)
実際に関数のインライン化を強制するのはコンパイラ次第で、特定のattribute
sまたはpragma
sまたは(__forceinline
)またはその他。
簡単に言えば、ODRを壊すことなくヘッダーで関数を定義できます...