15

Clang、GCC、またはその両方に対してバグレポートを提出するかどうかを判断しようとしています(ClangトランクとGCC 4.7.2に対してテストしました:誰かがGCCトランクに対してこれを検証できれば役立つでしょう):

-fsyntax-only基本的に、次のコード3行ファイルは、デフォルトモードとC++11モードで正常にコンパイルされます。

class A {
    friend void f();
};

の事前の宣言はありませんf()が、これは明示的にOKであることに注意してください。

ただし、Clang(GCCではない)は以下を拒否します。

class A {
    friend void ::f();
};

Clangからのエラーは、「指定されたスコープでタイプ「void()」の「f」という名前の関数が見つかりませんでした」ですが、このケースを前のケースとは異なる方法で処理するための標準には正当な理由が見つかりません。バグだと思います。しかし、私は間違っているかもしれません(ただし、N3242から読んでいますが、どのAFAIKがC ++ 11より前の最後の公開ドラフトです)。

ただし、この次の例は、ClangではなくGCCによって拒否されます。

void f() { }

void g()
{
    class A {
        friend void ::f();
    };
}

GCCからのエラーは、「事前宣言のないローカルクラスのフレンド宣言'void f()'」です。これは、宣言されているグローバル名前空間でをvoid ::f()参照する必要があるため、意味がないようです。f()friendローカルクラスからグローバル関数を実行することは無意味であり、違法ではないように思われることを気にしないでください...)

最後に、この最後の例はClangとGCCの両方によって拒否されます。

void g()
{
    class A {
        friend void ::f();
    };
}

エラーは、それぞれ「事前宣言のないローカルクラスのフレンド宣言'void f()'」と「指定されたスコープでタイプ'void()'の'f'という名前の関数が見つかりませんでした」です。さて、11.4p11から、ローカルクラスで以前に宣言されていない関数のフレンド宣言を拒否することにはある程度の正当性があるように見えますが、段落には実際には次のように書かれています。

フレンド宣言がローカルクラス(9.8)に表示され、指定された名前が非修飾名である場合、最も内側の非クラススコープの外側にあるスコープを考慮せずに、以前の宣言が検索されます。フレンド関数宣言の場合、事前の宣言がない場合、プログラムの形式が正しくありません...

この宣言の違法性は、この段落の2番目の文に基づいているようですが、この場合に使用されているように、修飾名の場合にもその文を適用する必要があるかどうかはわかりません。(おそらく、「非修飾名」が使用されているかどうかに関係なく、段落全体が「ローカルクラス」の場合に適用され、「指定された名前は非修飾名である」という句は、説明されているルックアップにのみ適用される可能性があります。最初の文では、それは一筋縄ではいかないようです...私がこれを可能性として想像している唯一の理由は、両方のコンパイラがそれを拒否するためです。)

とにかく、私が言えることから、これらの4つのケースはすべて(どれほど賢明であるかどうかに関係なく)合法であるはずです。そうでない場合でも、2番目と3番目のケースではClangとGCCの少なくとも1つが間違っています。誰かが私のロジックにエラーを見つけることができますか?

3番目と4番目のケースは明らかに無意味です。しかし、2番目のケースが誰かの有効で有用なコードを壊しているのを見ることができるので、それが本当にバグであるとしても、それが決して捕らえられなかったことに少し驚いています。

4

1 に答える 1

4

8.3/1のこの文は適切だと思います。

declarator-idが修飾されると、宣言は、修飾子が参照するクラスまたは名前空間の以前に宣言されたメンバー(または、名前空間の場合は、その名前空間のインライン名前空間セットの要素(7.3 .1))またはその専門分野。メンバーは、declarator-idのnested-name-specifierによって指定されたクラスまたは名前空間のスコープ内のusing-declarationによって単に導入されたものであってはなりません。

この段落では、宣言者全般について、あらゆる種類の宣言について説明しています。したがって、例2と4は形式が正しくなく、clangは正しく、gccは間違っていると思います。

(グローバル宣言がテンプレート関数である場合、例3はより現実的になる可能性があります。グローバル関数テンプレートまたはローカルクラスからの特殊化をフレンドリングすると便利な場合があります。それが許可されている場合は、記述されている例3も合法である可能性があります。一貫性。)

于 2013-03-15T05:25:59.533 に答える