C++03 と C++11 は、[temp.friend] の最初の段落にあります。
【引用修正しました。最初の試みは、言葉遣いの 2 番目の違いを見逃しました。]
テンプレート宣言ではないフレンド関数宣言の場合:
フレンドの名前が修飾または非修飾のtemplate-idである場合、フレンド宣言は関数テンプレートの特殊化を参照します。
フレンドの名前が修飾 IDであり、一致する非テンプレート関数が指定されたクラスまたは名前空間で見つかった場合、フレンド宣言はその関数を参照します。
[C++03:] フレンドの名前が修飾 IDであり、関数テンプレートの一致する特殊化が指定されたクラスまたは名前空間で見つかった場合、フレンド宣言はその関数テンプレートの特殊化を参照します。
[C++11:] フレンドの名前が修飾 IDであり、一致する関数テンプレートが指定されたクラスまたは名前空間で見つかった場合、フレンド宣言はその関数テンプレートの推定特殊化を参照します。それ以外の場合は、
名前は、通常の (非テンプレート) 関数を宣言 (または再宣言) する unqualified -idでなければなりません。
[文言の変更は、私には明確化のように見えます。「クラスまたは名前空間で特殊化を見つける」というC++03の表現を解釈するには、さまざまな方法があると思いますが.]
私はその 3 番目の弾丸が気になります。私はこのコードを書いてその要件に合わせようとしましたが、g++ 4.8.1 と clang++ 3.4 の両方が、-std=c++03 または -std=c++11 のどちらを指定しても、コードを拒否します。
template <class T> class R;
namespace N {
template <class T> void test(const R<T>&);
}
template <class T>
class R {
friend void N::test(const R<T>&); // 8
int m;
};
template <class T>
void N::test(const R<T>& rec) { rec.m; }
int main() {
R<int> r;
N::test(r);
}
もちろん、8行目を次のように変更すると
friend void N::test<>(const R<T>&);
最初の箇条書きが適用され、プログラムが受け入れられます。g++ は、友人が「非テンプレート関数を宣言している」という有益な警告を出力し、まさにそれを行いたいと示唆しています。コードは、明快さと安全性のために、おそらくより多くのスタイル ポイントを取得するでしょう。
しかし、上記のコードは 3 番目の箇条書きでカバーされ、有効であるべきではありませんか? フレンド宣言はテンプレート宣言ではなく、テンプレートIDではない修飾 IDを名前として使用しています。また、2 番目の箇条書きに一致するテンプレート以外の関数宣言はありません。
これは、両方に共通する単なるコンパイラのバグですか? または、私は何かを誤解していますか? もしそうなら、その 3 番目の箇条書きを示すプログラムの例はありますか?