6

次のコードでは、予期されるコンパイラ エラーが発生します ( Demo )。

  1 template<bool> struct Range;
  2 
  3 template<int value, typename = Range<true> > struct Unique;
  4 template<int value> struct Unique<value, Range<(value > 1)> > { typedef char type[1]; };
  5 template<int value> struct Unique<value, Range<(value > 2)> > { typedef char type[2]; };
  6 
  7 Unique<3>::type o1;
  8 Unique<3>::type o2;

ここで、5 行目と 7 行目を入れ替えるとします。次に、コンパイラエラーはありません!! デモ

  5 Unique<3>::type o1;

  7 template<int value> struct Unique<value, Range<(value > 2)> > { typedef char type[2]; };

の場合o1、特殊化(value > 2)がまだ表示されていないため、エラーがないことは理解できます。o2しかし、 2 つの一致する特殊化が表示されるエラーが発生しないのはなぜですか!?
私の推測では、コンパイラは、Unique<3>::type初めて遭遇したときに任意の名前を選択しUnique<3>::type、その名前ですべてを置き換える必要があります。

これはコンパイルのバグですか、それとも C++ のバグですか、それとも C++ の「機能」ですか?

4

3 に答える 3

3

テンプレートは、毎回ではなく、(翻訳単位で) 最初に必要になったときにインスタンス化されます。

于 2012-03-06T11:16:24.177 に答える
2

o1このため、2 番目の特殊化は表示されません。

14.5.5/1部分的な特殊化は、クラス テンプレートの特殊化を最初に使用する前に宣言する必要があります。これは、そのような使用が発生するすべての翻訳単位で暗黙的または明示的なインスタンス化の結果として部分的な特殊化を使用します。診断は必要ありません

2 番目の例では、2 番目の特殊化がUnique<3>の宣言の前に見られた場合、 のインスタンス化で使用されますo1。この規則に違反しているため、プログラムは壊れており、コンパイラはそれについて沈黙することが許されています。

o2特殊化がまったく表示されないため、2 番目の特殊化は表示されません。o1そのクラスは、宣言の時点で 1 回インスタンス化されます。

于 2012-03-06T14:43:35.780 に答える
2

14.5.5.1クラス テンプレートの部分的特殊化のマッチングには、

一致する特殊化が複数見つかった場合は、半順序規則 (14.5.5.2) を使用して、特殊化の 1 つが他の特殊化よりも特殊化されているかどうかを判断します。どの特殊化も、一致する他のすべての特殊化よりも特殊化されていない場合は、クラス テンプレートの使用があいまいであり、プログラムの形式が正しくありません。

ただし、これは 2 つの専門分野が表示されている最初のケースにのみ適用され、これら 2 つの専門分野自体が有効かどうかはまだわかりません。

ただし、2 番目のケースでは、2 番目の特殊化に到達する前に、テンプレート ID Unique<3>が既に存在し、(nm、Matthieu M.、James Kanze に感謝) 最初の特殊化が既にインスタンス化されています。

14.5.5 クラス テンプレートの部分的な特殊化

部分的な特殊化は、クラス テンプレートの特殊化を最初に使用する前に宣言する必要があります。これは、そのような使用が発生するすべての翻訳単位で暗黙的または明示的なインスタンス化の結果として部分的な特殊化を使用します。診断は必要ありません。

そして14.5.5では、項目8

クラス テンプレートの部分的な特殊化の引数リスト内では、次の制限が適用されます。

— 引数式が単純な識別子である場合を除き、部分的に特殊化された非型引数式は、部分的な特殊化のテンプレート パラメーターを含んではなりません。[ >例:

template <int I, int J> struct A {};

template <int I> struct A<I+5, I*2> {}; // error

template <int I, int J> struct B {};

template <int I> struct B<I, I> {}; // OK

—終わりの例]

したがって、単純な識別子として使用されない場合、型以外の引数は特殊化の作成に参加しないようです (したがってRange<(value > 2)>、間違っているでしょう)。

したがって、コードの形式が正しくないようです。


直接関係はありませんが、この点に関しては興味深い:

14.7.3 明示的な特殊化

関数テンプレート、クラス テンプレート、クラス テンプレートのメンバー関数、クラス テンプレートの静的データ メンバー、クラス テンプレートのメンバー クラス、クラス テンプレートのメンバー クラス テンプレート、クラス テンプレートのメンバー関数テンプレート、メンバーのメンバー関数の明示的な特殊化宣言の配置クラス テンプレートのテンプレート、非テンプレート クラスのメンバー テンプレートのメンバー関数、クラス テンプレートのメンバー クラスのメンバー関数テンプレートなど、およびクラス テンプレートの部分特殊化宣言の配置、非テンプレート クラスのメンバー クラス テンプレート、メンバークラステンプレートのクラステンプレートなどは、相対的な位置付けに従ってプログラムが整形式であるかどうかに影響を与える可能性があります上および下で指定されているように、明示的な特殊化宣言と翻訳単位でのそれらのインスタンス化のポイント。専門化を記述するときは、その場所に注意してください。またはそれをコンパイルすることは、その自己犠牲を燃やすような試練になるでしょう.

于 2012-03-06T11:23:16.047 に答える