2つの関数テンプレート宣言が同じテンプレートを宣言するのか、それとも同じ名前のオーバーロードであるのかを決定するのは何ですか?
答えの始まりは3.5p9にあります:
同じであり(条項3)、異なるスコープで宣言されている2つの名前は、同じ変数、関数、型、列挙子、テンプレート、または名前空間を示すものとします。
両方の名前に外部リンケージがあるか、両方の名前に内部リンケージがあり、同じ翻訳単位で宣言されています。と
両方の名前は、同じ名前空間のメンバー、または継承ではなく同じクラスのメンバーを参照します。と
両方の名前が関数を表す場合、関数(8.3.5)のパラメータータイプリストは同一です。と
両方の名前が関数テンプレートを示す場合、シグニチャ(14.5.6.1)は同じです。
非テンプレート非メンバー関数のシグネチャは(1.3.17)です。
サイン
<関数>名、パラメーター型リスト(8.3.5)、および囲んでいる名前空間(存在する場合)
[注:署名は、名前のマングリングとリンクの基礎として使用されます。-エンドノート]
すでに2回言及されているparameter-type-listは、セクション8.3.5p5で定義されています。この段落では、宣言された型から関数パラメーターの実際の型を調整する方法、配列と関数をポインターに置き換える方法、および最上位のcv修飾子を破棄する方法について説明します。それで、
結果として得られる変換されたパラメーター型のリストと、省略記号または関数パラメーターパックの有無は、関数のparameter-type-listです。
したがって、非テンプレートの場合、parameter-type-listは、トークンのシーケンスや構文構造ではなく、明らかにタイプの概念的なセマンティックリストです(さらに、派手な終わりかもしれません)。そして、以下は、予想どおり、両方の定義が同じ関数を定義しているため、ODRの違反です。
void f(int, int*) {}
void f(int p, decltype(p)*) {}
テンプレートの場合、(1.3.18)があります。
サイン
<関数テンプレート>名前、パラメーター型リスト(8.3.5)、名前空間(存在する場合)、戻り型、およびテンプレートパラメーターリスト
今考えてみましょう:
template<typename T> void g(int, int*, T, T*) {} // #1
// template<typename T> void g(int p, decltype(p)*, T, T*) {} // #2
template<typename T> void g(int, int*, T q, decltype(q)*) {} // #3
g ++ -std = c ++ 0xバージョン4.6.3は、定義#1と#2が同じ関数を定義していると文句を言いますが、#1と#3をオーバーロードとして受け入れることに問題はありません。(また、#3は#1よりも特殊であり、#1を呼び出す方法はありませんが、これは接線の問題です。)#2と#3の主な違いは、q
タイプに依存し、そうでp
はないことです。decltype(q)
それで、テンプレートがインスタンス化されるまで、の意味を決定できないと思いますか?この動作は標準によって保証されていますか?
関数テンプレートの場合、parameter-type-listの意味には、インスタンス化によってまだ置き換えられていないテンプレートパラメーター、つまり依存する名前などを含めることができる必要があります。しかし、それでは、可能であれば、2つの宣言が同等であるかどうかを知るのが難しくなります。
同様の問題は、同等の式と同等の関数テンプレート宣言(異なる宣言がテンプレートパラメーターに異なる識別子を使用する場合があることを除いて、トークンの同じシーケンス)、機能的に同等の式、および機能的に同等の関数テンプレートを定義する14.5.6.1段落5〜6によって解決されます。宣言(インスタンス化後も同じ)、要件:
プログラムに、機能的には同等であるが同等ではない関数テンプレートの宣言が含まれている場合、プログラムの形式は正しくありません。診断は必要ありません。
段落5の例は、安全に同等の関数テンプレートを示しています。
template <int I, int J> void f(A<I+J>); // #1
template <int K, int L> void f(A<K+L>); // same as #1
段落7の例は、その規則の違反を示しています。
// Ill-formed, no diagnostic required
template <int I> void f(A<I>, A<I+10>);
template <int I> void f(A<I>, A<I+1+2+3+4>);
g
ただし、これは上記のサンプル関数 には適用されません。T*
型の同等性の類似した定義の下では機能的に同等であると見なされる可能性がありdecltype(q)*
ますが、セクション14.5.6.1は、型ではなく式の置換のみを説明しています。