コンパイラは一度に 1 つのファイルをコンパイルします。コンパイラが解析しているソース ファイルには他のファイルが含まれている場合がありますが、含まれているすべてのファイルはコンパイル前の段階で単一のソースに "フラット化" され、コンパイラは 1 つのコード エンティティを "認識" します。
上記により、コンパイラはその区別をしないため、コードが .cpp または .h ファイルにあるかどうかはコンパイラにとって重要ではありません。ただし、関数定義または変数定義が .h ファイルにある場合、リンク段階で問題が発生します。
リンカはソース ファイルを認識しませんが、コンパイラが生成する結果であるオブジェクト ファイル (.obj) を認識します。リンカーは、各オブジェクト ファイル内のすべての関数とすべての変数を認識しており、リンカーの仕事は、それらを 1 つの実行可能ファイルにまとめてバインド (またはリンク) することです。異なるオブジェクト ファイルに同じ名前の変数または関数が複数ある場合、リンカはそれらの処理方法を失い、エラーを宣言します。すべての余分な変数と関数を無視するオプションをリンカーに強制することは可能ですが、そのオプションは安易に使用しないでください。同じ名前の 2 つの関数は、実際には完全に異なる場合があり、そのうちの 1 つを無視すると、あらゆる種類のエラーが発生します。
一方、テンプレートは関数ではありません。これらは実際の機能の設計図です。コンパイラがテンプレートに遭遇しても、実質的なことは何も起こりません。テンプレートが実際の関数にインスタンス化された場合にのみ、コンパイラはそのような関数を作成します。このため、テンプレートはヘッダー ファイルに問題なく配置できます。