10

以下が GCC のバグであり、私の C++ の理解にないことを確認したいと思います。次のコードを検討してください。

struct A
{
    struct B
    {
        template< typename U > U as() const { return U(); }
    };

    B operator[]( int ) const { return B(); }
};

template< typename T >
struct as
{
    template< typename U >
    static T call( const U& u )
    {
        return u[ 0 ].as< T >(); // accepted by Clang 3.2, rejected by GCC 4.7
        // return u[ 0 ].template as< T >(); // does not help and is IMHO not needed
        // return u[ 0 ].A::B::as< T >(); // accepted by GCC 4.7
    }
};

int main()
{
    as< int >::call( A() );
}

IMHOコードは問題ないはずです。Clang 3.2では受け入れられますが、GCC 4.7では受け入れられません(4.4と4.6も基本的に同じエラーで失敗しますが、4.4ではわずかに異なるメッセージが生成されます)。私のシェルからの出力は次のとおりです。

$ clang++-3.2 -O3 -Wall -Wextra -std=c++0x t.cc -o t
$ g++-4.7 -O3 -Wall -Wextra -std=c++0x t.cc -o t
t.cc: In static member function ‘static T as<T>::call(const U&)’:
t.cc:17:21: error: invalid use of ‘struct as<T>’
t.cc: In static member function ‘static T as<T>::call(const U&) [with U = A; T = int]’:
t.cc:18:4: warning: control reaches end of non-void function [-Wreturn-type]
$ 

質問:これは GCC のバグですか、それとも何か不足していますか?

編集:私は少し混乱しています: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55576の GCC バグ レポートは、コメント #9 で、コメント #3 のコードは「有効」であると述べています。これは正確にはどういう意味ですか?GCC の人々はそれが実際にバグであると考えているようです。そうでなければ、すでに閉じていたでしょうか? OTOH@Potatoswatterからの回答は、それが正しいはずであり、Clangに対してバグレポートを提出する必要があることは非常に明確であるようです(または、そのようなバグレポートは既にありますか?)

上記が明確になるまで、回答を承認済みとしてマークすることをためらうことに注意してください。両方の回答が既に役に立っているので (1 つは説明、もう 1 つは回避策)、私は両方に賛成票を投じました。

おまけの質問: 非物語的なコードに反対票を投じられたので、他の人はどう感じているのだろうか。気を散らすものをすべて取り除き、技術的な問題に集中する SCCEE を作成しようとしました。それが私がこれらのことについて考えるのを好む方法です。それは間違っていますか?

また、@EdHeal: コードが災害を起こしやすいのはなぜですか? (それは私が持っている実際のコードではないと思いますよね?)

EDIT2:ありがとう、David、あなたの編集に気づきました。あなたの回答を承認済みとしてマークします。また、GCC バグ レポートについてコメントしたことも確認しました。これにより、この質問の要点が答えられ、GCC は別のリマインダーを得たと思います。みんな、ありがとう。

4

2 に答える 2

5

これは言語のトリッキーなコーナーです。GCCはC++03§3.4.5/1のルールを適用しています。

クラスメンバーアクセス式(5.2.5)で、.or->トークンの直後に識別子の後にaが続く場合は、識別子を検索して、がテンプレート引数リストの先頭(14.2)以下である<かどうかを判断する必要があります。<-演算子より。識別子は、最初にオブジェクト式のクラスで検索されます。識別子が見つからない場合は、postfix-expression全体のコンテキストで検索され、クラスまたは関数テンプレートに名前が付けられます。オブジェクト式のクラスでのルックアップでテンプレートが見つかった場合、名前はpostfix-expression全体のコンテキストでもルックアップされます。

—名前が見つからない場合は、オブジェクト式のクラスで見つかった名前が使用されます。それ以外の場合は、

—名前がpostfix-expression全体のコンテキストで見つかり、クラステンプレートに名前が付けられていない場合は、オブジェクト式のクラスで見つかった名前が使用されます。それ以外の場合は、

—見つかった名前がクラステンプレートの場合、オブジェクト式のクラスで見つかったものと同じエンティティを参照する必要があります。そうでない場合、プログラムの形式が正しくありません。

部分式のタイプはテンプレート引数に依存するためtemplate、トークンを明確にするためにキーワードがすでに必要であるため、このプロセスは役に立たなかったことに注意してください。<u[0]

このようにする理由は、template-idがネストされた名前修飾子で使用されている場合の解析を単純化するためです。たとえばu[ 0 ].as< T >::bar.bazbarは基本クラスへのtypedefです。

C ++ 11は、3つの箇条書きを削除し、プロセスを簡素化します。

識別子は、最初にオブジェクト式のクラスで検索されます。識別子が見つからない場合は、postfix-expression全体のコンテキストで検索され、クラステンプレートに名前が付けられます。

つまり、これはバグであり、前に言ったような古いものではありません。名前検索のコーナーケースを削除する必要があります。

また、この癖を利用して、単一のテンプレート式がクラスまたは関数を交互に参照できるようにすることができるようです。それが役立つかどうかはわかりませんが、C++11の新機能です。

于 2013-02-25T11:47:59.587 に答える
1
于 2013-02-25T11:22:04.697 に答える