11

このコードが無効だったらいいのにと思います。しかし、それは概念的には健全であり、Comeauは受け入れませんが、GCCはそれを受け入れます。

template< typename > struct t;

template<> struct t< int > {} r; // Bad declarator! Don't pee on the carpet!

編集:上記はコンパイルされますが、どのスコープrにも宣言されていないようですので、基本的に無視されます。)

明示的な特殊化は、テンプレートとクラスの間の一種のネザー領域に入力されます。明示的な特殊化によって宣言された型は、定義されると完了します。コンパイラの観点からは、これはテンプレートではありません。パラメータ化されたテンプレートの場合、オブジェクトを宣言することは不可能です。§14/3を検討してください:

テンプレート宣言、明示的な特殊化、または明示的なインスタンス化では、宣言内のinit-declarator-listに最大で1つの宣言子を含める必要があります。このような宣言を使用してクラステンプレートを宣言する場合、宣言子は許可されません。

「クラステンプレートの宣言に使用される」とはどういう意味ですか?明らかに、プライマリテンプレートはクラステンプレートを宣言します。また、§14.5.5/ 1(FDIS番号)によると、部分的な特殊化も同様です。

クラステンプレート名がsimple-template-idであるテンプレート宣言は、simple-template-idで指定されたクラステンプレートの部分的な特殊化です。

ただし、明示的な特殊化に関しては、標準はトークンシーケンスが前に付いた宣言の観点から説明していますtemplate<>。テンプレートのように見え、template-nameという名前が付けられていますが、テンプレートを宣言していないようです。

本当に奇妙なことは、§14/3が宣言者の数を「最大で1つ」に制限していることです。関数テンプレート宣言、明示的な特殊化、またはインスタンス化には、宣言子が1つだけ必要です。クラステンプレートを含むすべての宣言は、正確にゼロでなければなりません…明示的な特殊化を除いて、それは亀裂を通り抜けているようです。忠実に、GCCは許可することを拒否します

template<> struct t< int > {} r, s; // Offer valid one per specialization.

私はGCCの解釈に同意する傾向がありますが、それはナンセンスかもしれません。残念ながら、欠落しているセミコロンを検出する機能が阻害されている可能性があります。許可される宣言子の数を正確にゼロにしてください。

4

2 に答える 2

13

いくつかのポイント:まず、明示的な特殊化は、テンプレートとクラスの間のネザー領域にはありません。明示的な特殊化は、クラス、期間です。テンプレートとの唯一の関係は(おかしな名前を除いて)、テンプレートが特殊化タイプでインスタンス化される場合、テンプレートのインスタンス化の代わりに使用されることです。

第二に、あなたが引用する§14/ 3の段落に問題がある場合、それは明示的なインスタンス化を含んでいるということです。明示的なインスタンス化はクラス定義であり、

struct S {} s, *p;

合法です、

template<> struct T<int> {} s, *p;

あまりにもあるはずです。(どちらかを許可することに反対しますが、その列車はすでに駅を出ており、Cが最初の列車を許可しているので、私たちはそれに固執しています。)

それ以外の場合、§14/3のステートメントは少し無関係です。関数テンプレートには正確に1つの宣言子が必要であり、クラステンプレートには正確にゼロが必要です。いくつかの「せいぜい1つ」のgobbledygookで両方をエングローブしようとする必要はありません。(言語を最初から設計している場合、クラスまたは列挙型を定義する宣言で宣言子を許可しません。しかし、繰り返しになりますが、それには遅すぎます。)

そして、私はそれが面倒であることに同意します:

template<> struct T<int> {};    //  Requires a ';'
template<> void f<int>() {}     //  ';' forbidden

(少なくともC ++ 11では、関数定義の後にセミコロンを使用できます。)

于 2011-06-10T09:43:10.453 に答える
1

明示的な特殊化と明示的なインスタンス化は、テンプレートを宣言しません。クラスである特殊化を参照するtemplate-idを宣言します。

ただし、これは私の例を検証しません。問題は、以下に宣言されているすべてtemplateのものが明示的なインスタンス化またはtemplate<>特殊化の一部であるということです。特定の種類のエンティティのみが特殊化またはインスタンス化される可能性があり、以前に宣言されていない名前はそれらの 1 つではありません。

これらの例を考えてみてください。これらの例では、精緻化された型指定子 (§7.1.5.3) を無償ではあるが合法的に使用しています。

template< typename T > struct s;
template< typename T > s< int > *f() {}

template<> struct u *f< char >(); // struct u is declared
u *p = 0; // see, we can use its name now.
template<> struct s< int > *f< int >(); // s<int> declared but not specialized
template struct s< int > *f< long >(); // s<int> declared but not instantiated

私が知る限り、どの宣言名が特殊化されたものであるかを指定することについて、標準はあいまいです。この言語は、そのような各宣言が 1 つのテンプレートのみに適用されることを弱く暗示しています: §14.7.2/2

明示的なインスタンス化がクラス、関数、またはメンバー テンプレートの特殊化のためのものである場合…</p>

および§14.7.3/2

明示的な特殊化は、テンプレートがメンバーである名前空間で宣言する必要があります…</p>

これを解決する唯一の方法は、宣言子が正当なインスタンス化/特殊化も指定している場合、型宣言を無視することです。

要点を言えば、質問の例では、宣言子で不正な特殊化を指定し、代わりにコンパイラがバックトラックして型を特殊化することを期待しています。§14.7.2/1 および §14.7.3/1 で許可されている特殊化と宣言の明示的なリストを考えると、それが関数テンプレート、メンバー関数テンプレート、静的データ メンバーではないtemplate<> struct t< int > {} r;ことについて不平を言う方が合理的です。rクラステンプレートなど

于 2011-06-20T18:30:52.393 に答える