Boost やその他のさまざまな C++ ライブラリを調べてきました。Boost の大部分はヘッダー ファイルに実装されています。
私の質問は次のとおりです。ヘッダーのみの実装 (Boost など) を行うのはどのような条件下ですか? または .cpp ファイルも含めますか?
Boost やその他のさまざまな C++ ライブラリを調べてきました。Boost の大部分はヘッダー ファイルに実装されています。
私の質問は次のとおりです。ヘッダーのみの実装 (Boost など) を行うのはどのような条件下ですか? または .cpp ファイルも含めますか?
別の翻訳単位(つまり、別のソースファイル)でテンプレートを使用する場合は、(ほとんどの場合)ヘッダーファイルでテンプレートを定義する必要があります。(以下のコメントが指摘するような例外がありますが、私見ではこれは大まかな目安です。)
別の変換ユニットのインライン関数を使用する場合も同様です。
それ以外の場合は、依存関係を最小限に抑えるために、実装を別の.cppファイルに配置する必要があります。
この問題を理解することは、基本的に C++ コンパイル ユニットがどのように機能するかを理解することです。#include
ヘッダー ファイル内のものは、基本的にステートメントごとに一連のコンパイル ユニットのソース コードに貼り付けられます。各コンパイル単位がオブジェクト ファイルにコンパイルされ、オブジェクト ファイルがリンクされ、その内容があちこちに複製されるため、競合が発生します。
例外は、(少なくとも歴史的には) コンパイラが直接処理するためオブジェクト ファイルに入れられないもの (インライン関数など) と、あるユニットでコンパイルしてから別のユニットにリンクできないものです。完全に定義されていません (テンプレート)。多くの場合、テンプレート関数は複数のコンパイル単位で同じようにインスタンス化され、リンカーには重複を破棄する特別な機能があります。
これは、インターフェイスと実装のヘッダー ファイルと本体ファイルへの分離がそれほど明確ではないことを意味します。Ada はより明確な分離を備えていますが、IIRC を補うためのビルド プロセスはより複雑です。Java は、インターフェースと実装用に別々のファイルを削除しただけです。
リンカは長年にわたってより洗練され、コンパイラの作業の一部を引き継いでいます。最近では、この説明の多くは単に間違っていますが、基本的なパターンは残っています. テンプレート関数とインライン関数は、すべての直接生成しないオブジェクト コード共有宣言と共に、ヘッダーに入れることができます (そしてしばしばそうする必要があります)。通常の関数定義はヘッダー ファイルに含めるべきではありません。