6

次のコードを検討してください。

template <int N>
struct X
{
 friend void f(X *) {}
};

int main()
{
 f((X<0> *)0); // Error?
}

コンパイラは大きく反対しているようです。(MSVC08/10 はノー、GCC<4.5 はイエス、4.5 はノー、sun 5.1 はイエス、インテル 11.1 もイエス、comeau はノー (どちらも EDG))。

「C++ テンプレート - 完全なガイド」によると:

... 関連付けられたクラス内のフレンドのルックアップを含む呼び出しにより、実際にクラスがインスタンス化されると想定されています ... これは、C++ 標準を作成した人々によって明確に意図されていましたが、標準では明確に記述されていません。

標準で関連するセクションが見つかりませんでした。参照はありますか?

次のバリエーションを検討してください。

template <int N>
struct X
{
 template <int M>
 friend void f(X<M> *) {}
};

template <>
struct X<0>
{
};

int main()
{
 X<1>();
 f((X<0> *)0); // Error?
}

ここでの重要な問題は、によって注入された実行可能な関数がX<1>ADL 中に表示されるX<0>かどうかです。それらは関連していますか?上記のすべてのコンパイラは、このコードを受け入れますが、Comeau はリラックス モードでのみ受け入れます。これについて標準が何を言わなければならないのかもわかりません。

それについてどう思いますか?

4

1 に答える 1

4

規格は次のように述べています14.7.1/4

完全に定義されたオブジェクト型を必要とするコンテキストでクラス型が使用される場合、またはクラス型の完全性がプログラムのセマンティクスに影響する場合、クラス テンプレートの特殊化は暗黙的にインスタンス化されます。特に、型がクラス テンプレートの特殊化である式がオーバーロードの解決、ポインター変換、ポインターからメンバーへの変換に関与する場合、クラス テンプレートの特殊化は暗黙的にインスタンス化されます (3.2)。

Vandervoorde がここで問題報告を行い、委員会が発見したことに注意してください。

標準では、これによりインスタンス化のポイントが作成されることが既に指定されています。

2 番目のケースでは、関連するクラスと引数の名前空間を考慮する必要がありますf(X<0>*)。これらは、これがクラス テンプレートの特殊化へのポインターであるため (以下の "template-id" は完全に正しくないことに注意してください - C++0x は正しい用語を使用するように修正しました)、クラスへのポインター (この紛らわしい分割) でもあります。 C++0x でも修正されました - これら 2 つのケースを 1 つの箇条書きにまとめています)。

  • T が template-id の場合、関連付けられた名前空間とクラスは、テンプレートが定義されている名前空間です。[...ノイズが多い...]

  • T がクラス型 (共用体を含む) の場合、関連するクラスは次のとおりです。 クラス自体。もしあれば、それがメンバーであるクラス。およびその直接および間接基本クラス。関連する名前空間は、関連するクラスが定義されている名前空間です。

要約すると、関連するクラスはX<0>あり、関連する名前空間はグローバル名前空間です。現在、表示されているフレンド機能は次のとおりです。

  • 関連付けられたクラスで宣言された名前空間スコープのフレンド関数は、通常のルックアップ中に表示されなくても、それぞれの名前空間内で表示されます

にフレンド関数が宣言されX<0>ていないため、グローバル名前空間を調べてもフレンド関数の宣言は表示されません。X<0>は とはまったく異なるクラスタイプであることに注意してくださいX<1>。you do thereの暗黙的なインスタンス化はX<1>、この呼び出しには影響しません。 class のフレンド関数を参照する非表示の名前をグローバル名前空間に追加するだけX<1>です。

于 2010-09-02T22:20:02.203 に答える