10

クラスのtemplate専門化を比較する手順は何ですか? この点に関する標準の詳細はありません (または、適切な場所がありません)。
私の質問は、インスタンス化中に使用する専門化を決定することとは何の関係もありません。それについてはコメントしないでください。問題は、専門化を互いに比較して、特定の専門化がすでに定義されているかどうかを判断することです。

次のサンプル コードを検討してください。

template <class x1, class x2>
struct CoreTemplate { };

template <class x1, class x2>
struct CoreTemplate<x1*, x2*> { int spec; CoreTemplate() { spec = 1; } };

template <class x1, class x2>
struct CoreTemplate<x2*, x1*> { int spec; CoreTemplate() { spec = 2; } };

int main(int argc, char* argv[])
{
    CoreTemplate<int*, int*> qq;
    printf("var=%d.\r\n", qq.spec);
}

このコードを MSVC でコンパイルしようとすると、main関数内でのインスタンス化の試行でエラーが発生します。

cpptest1.cxx(15): エラー C2752: ' CoreTemplate<x1,x2>': 複数の部分的な特殊化がテンプレート引数リストと一致します

私にとっては、同一のテンプレートの特殊化を宣言しようとすると、エラーを発行する方が論理的です。上記の専門分野に違いはありません。

では、テンプレートの特殊化を比較するルールを知っている人はいますか? 記事、リンク、書籍なども役立ちます。

4

3 に答える 3

5

標準は、テンプレートをインスタンス化しようとしたときにのみこれが発生することを明確に示しています (§14.5.4.1/1):

クラスのインスタンス化が必要なコンテキストでクラス テンプレートが使用される場合、インスタンス化がプライマリ テンプレートを使用して生成されるか、部分的な特殊化の 1 つを使用して生成されるかを決定する必要があります。【強調追加】

残念ながら、インスタンス化中に使用する専門化を決定する方法を議論せずに、残りの質問に答えることはできません。標準のテキストは次のとおりです (上記の抜粋からの続き)。

これは、クラス テンプレートの特殊化のテンプレート引数を、部分的な特殊化のテンプレート引数リストと一致させることによって行われます。

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

そのため、テンプレートを互いに直接比較しようとすることはまったくありません。むしろ、指定された引数に一致する特殊化を見つけようとします。一致するものが複数ある場合は、部分的な順序付け規則に基づいて、最も特殊化されたものを選択しようとします。どちらも特殊化されていない場合、インスタンス化はあいまいであり、コンパイルは失敗します。

さて、これらの特殊化のどちらも使用できないということは確かに真実です。なぜなら、常にあいまいさが存在するからです。ただし、コンパイラがそれを検出または診断する必要はまったくありません。この正確なケース (本質的に同一の特殊化) ではおそらく簡単ですが、それがはるかに難しい他のケースがほぼ確実に存在するため、(明らかに) 委員会はコンパイラが試す必要さえないと判断しました。

于 2012-06-21T06:47:14.333 に答える
1

ああ、でも同じパラメーターを使用していないため、同じではありませんclang と元の例を使用します。

#include <cstdio>

template <class x1, class x2>
struct CoreTemplate { };

template <class x1, class x2>
struct CoreTemplate<x1*, x2*> { int spec; CoreTemplate() { spec = 1; } };
// note: partial specialization matches [with x1 = int, x2 = int]

template <class x1, class x2>
struct CoreTemplate<x2*, x1*> { int spec; CoreTemplate() { spec = 2; } };
// note: partial specialization matches [with x1 = int, x2 = int]

int main()
{
    CoreTemplate<int*, int*> qq;
    // error: ambiguous partial specializations of 'CoreTemplate<int *, int *>'
    std::printf("var=%d.\r\n", qq.spec);
}

ただし、完全に一致するように部分的な特殊化を微調整すると、次のようになります。

template <class x1, class x2>
struct Core { };

template <class x1>
struct Core<x1*, x1*> { int spec; Core() { spec = 1; } };
// note: previous definition is here

template <class x1>
struct Core<x1*, x1*> { int spec; Core() { spec = 2; } };
// error: redefinition of 'Core<type-parameter-0-0 *, type-parameter-0-0 *>'

したがって、実装の品質の問題のようです。コンパイラは最初のケースで警告を発する可能性がありますが、一般的なケースではリソースを消費するか、これまで誰もその必要性を表明していない可能性があります。

于 2012-06-21T06:54:46.980 に答える
0

私にとっては、同一のテンプレートの特殊化を宣言しようとすると、エラーを発行する方が論理的です。

CoreTemplate<int*, double*>andCoreTemplate<double*, int*>は異なる型を生成するため、それは起こりません。

以下は私の推測です:コンパイラは、本体に対して追加の健全性/常識的なチェックを
行わない場合があります。 をインスタンス化すると、その時点でコンパイラは一致する型を検索し、最適なものを選択します。one のみに一致しない場合、 no-matchまたはmultiple-matchのいずれかでコンパイラ エラーが発生します。template
template

例えば:

template<typename T>
void foo ()
{
  T::x();
}

int main ()
{
}

C++ プログラム全体で関数名が 1 つもないことがわかっていても、問題なくコンパイルできますx()。コンパイラは、foo<T>.

main()また、2 つの特殊化の間に配置して例を少しひねると、完全に正常にコンパイルされます。

于 2012-06-21T06:26:16.793 に答える