複数の定義については、非テンプレート関数はテンプレートとは異なる扱いをするのはなぜですか?
ここには歴史的な互換性の問題があります。いくつかの要件はCから来ています、それはそれが働く方法です。また、テンプレートとは何か、それらはコードジェネレータに関する理由もあります。必要に応じて、コンパイラはコードを生成する必要があるため、コード生成時にコードを参照する必要があります。これには複数の定義が存在するというノックアウトがあるため、これらの問題を解決するためのルールが必要です。
簡単に言えば、テンプレートはプログラム内で単一の定義を持っているかのように振る舞います(つまり、inline
と宣言されていない) - 特にw.r.t.機能。非テンプレートがinline
と宣言されている場合、同様の現象が発生します。
ここには標準的な参照が含まれています。
いくつかの背景、ここでの問題の大部分は、リンケージとは何ですか、リンケージとは何ですか?
プログラム全体と各翻訳単位の関数と変数に関するいくつかの一般規則。
§3.2/1 [basic.def.odr]
ませ翻訳単位は、任意の 変数、関数、クラス型、列挙型、またはテンプレートの複数の定義を含まないものとします。
そして
§3.2/4 [basic.def.odr]
すべてのプログラムは...
をそのプログラムにODR-使用されているすべての非インライン関数や変数の正確に一つの定義を含まなければなりません§3.2/6 [basic.def.odr]
クラス型(句[クラス])、列挙型([dcl.enum])、外部リンケージ([dcl.fct.spec])を持つインライン関数、クラステンプレート(句[クラステンプレート([temp.static])のメンバ関数、テンプレート([temp.mem.func])のメンバ関数、特定のテンプレートパラメータが指定されていない([temp.spec]、[temp.class.spec])プログラムでは、各定義が異なる翻訳単位で表示され、定義が次の要件を満たしている必要があります。
D
がテンプレートであり、複数の翻訳単位で定義されている場合、前述の要件は、テンプレート定義で使用されるテンプレートの囲みスコープの名前に適用されます([temp.nonde p])、インスタンス化時点の従属名([temp.dep])にも適用されます。 D
の定義がこれらの要件をすべて満たしている場合、その動作は1つの定義がD
であるかのようになります。 D
の定義がこれらの要件を満たしていない場合、その動作は定義されていません。
クラスを含む上記のリスト上のいくつかの非公式の観察、テンプレートなどは、これらのことが多い(もちろん排他的ではないか、ヘッダに限る)ヘッダファイルに見られる典型的な要素です。彼らは、すべてが期待どおりに動作するように、これらの特別なルールが与えられています。
クラスメンバー関数についてはどうですか? §9.3 [class.mfct]
1 /メンバ関数を定義することができる([dcl.fct.def])は、インラインメンバ関数([dcl.fct.spec])である場合には、そのクラス定義において、すでに宣言されていてクラス定義で定義されていない場合は、そのクラス定義の外部で定義されている可能性があります。クラス定義の外に出現するメンバ関数定義は、クラス定義を囲む名前空間スコープ内に現れなければならない。...
2 /インラインメンバ関数(静的であれ非静的であれ)クラス定義内の宣言またはクラス定義外の定義を指定すると、関数はinline
またはconstexpr
と宣言されます。 [注:名前空間スコープ内のクラスのメンバー関数は、そのクラスのリンケージを持っています。ローカルクラス([class.local])のメンバー関数にはリンケージはありません。 [basic.link]を参照してください。 - エンドノート]
だから基本的には、メンバ関数は、クラス定義で定義されていない暗黙的inline
ない、したがって、「通常」のルールが適用されますので、一度だけのプログラムで表示することができます。
テンプレートとは何でしょうかリンケージ?3210
テンプレート名にリンケージ([basic.link])があります。内部リンケージを持つテンプレートの特殊化(明示的または暗黙的)は、他の翻訳単位のすべての専門化とは異なります。テンプレート定義は、1つの定義ルール([basic.def.odr])に従います。
タイトルの質問にもかかわらず、これは重複した質問ではありません。これは、ヘッダーにテンプレートコードがあると、重複した定義がリンカーエラーの原因となるのではなく、なぜシンボルが欠落しているのではないのでしょうか。 – Niall