14

C++03 と C++11 は、[temp.friend] の最初の段落にあります。

【引用修正しました。最初の試みは、言葉遣いの 2 番目の違いを見逃しました。]

テンプレート宣言ではないフレンド関数宣言の場合:

  1. フレンドの名前が修飾または非修飾のtemplate-idである場合、フレンド宣言は関数テンプレートの特殊化を参照します。

  2. フレンドの名前が修飾 IDであり、一致する非テンプレート関数が指定されたクラスまたは名前空間で見つかった場合、フレンド宣言はその関数を参照します。

  3. [C++03:] フレンドの名前が修飾 IDであり、関数テンプレートの一致する特殊化が指定されたクラスまたは名前空間で見つかった場合、フレンド宣言はその関数テンプレートの特殊化を参照します。

    [C++11:] フレンドの名前が修飾 IDであり、一致する関数テンプレートが指定されたクラスまたは名前空間で見つかった場合、フレンド宣言はその関数テンプレートの推定特殊化を参照します。それ以外の場合は、

  4. 名前は、通常の (非テンプレート) 関数を宣言 (または再宣言) する 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 番目の箇条書きを示すプログラムの例はありますか?

4

3 に答える 3

1

//8 行目で、コードを次のように変更し friend void N::test< R<T> >( R<T>&); ました。これも正しいです。

friend void N::test<R<T>>(const R<T>&);//one type is friend with one type  #1
friend void N::test<>(const R<T>&);// one type is friend with one type    #2

#1 が #2 に等しいというコード証明を使用します

最後に、あなたの質問に答えようと思います。それが正しいかどうかはわかりません。

 friend void N::test(const R<T>&);

クラス R をインスタンス化するときR<T>は、既知の型です。ただし、機能は

フレンド関数として宣言され、関数テンプレートを実際にインスタンス化しない場合、

フレンド機能は存在しない機能です。文法の観点からは、

コンパイラは、それがテンプレートではなく関数であることを確認します

N::test (r);

この場所で関数はインスタンス化されますが、コンパイラは

R でテンプレートとして宣言しないため、R クラスでの宣言の前に friend

クラスでは、関数を宣言するだけです。

于 2014-11-17T10:22:40.347 に答える
0

14.8.2.6から、<>が減点の条件だと思いますので、

declarator-id が関数テンプレートの特殊化を参照する宣言では、宣言が参照する特殊化を識別するために、テンプレート引数推定が実行されます。具体的には、これは明示的なインスタンス化 (14.7.2)、明示的な特殊化 (14.7.3)、および特定のフレンド宣言 (14.5.4) に対して行われます。

この場合、declarator-id は特殊化されていないため、控除は行われません。

于 2013-10-24T16:52:03.020 に答える
0

N::test は、 というクラスを取るテンプレート化された関数ですT。というクラスは取りませんR<T>。関数を適切に変更すると、機能します。

namespace N
{
    template <class T>
    void test ( const T & );
}

template <class T>
class R
{
    friend void N::test ( const R<T> & );
    int m;
};

template <class T>
void N::test ( const T & rec ) { rec.m; }

int main ( )
{
    R<int> r;
    N::test ( r );
}
于 2014-09-07T20:08:09.387 に答える