43

-fpermissive オプションなしではコンパイルできなくなった C++ コードがいくつかあります。共有できない適切なコードですが、問題を示す簡単なテスト ケースを抽出できたと思います。g++ からの出力は次のとおりです。

template_eg.cpp: In instantiation of 'void Special_List<T>::do_other_stuff(T*) [with T = int]':
template_eg.cpp:27:35:   required from here
template_eg.cpp:18:25: error: 'next' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
template_eg.cpp:18:25: note: declarations in dependent base 'List<int>' are not found by unqualified lookup
template_eg.cpp:18:25: note: use 'this->next' instead

したがって、問題を生成するコードは次のとおりです。

template<class T> class List  
{
        public: 
        void next(T*){
            cout<<"Doing some stuff"<<endl;
        }       
};

template<class T> class Special_List: public List<T>
{
    public:
        void do_other_stuff(T* item){
                next(item);
        }       
};


int main(int argc, char *argv[])
{
    Special_List<int> b;
    int test_int = 3;
    b.do_other_stuff(&test_int);
}

コードを修正して再度コンパイルする方法を見つけようとしているわけではありません。これは単に next(item) を this->next(item) に変更するだけの問題です。この変更が必要な理由をよりよく理解しようとしています。このページで説明を見つけました: http://gcc.gnu.org/onlinedocs/gcc/Name-lookup.html その説明は役に立ちましたが、まだいくつか質問があります。私の関数が T* (型 T へのポインタ) を取るという事実は、それをテンプレート引数に依存させるべきではありません。私自身の言い回しでは、コンパイラ (gcc 4.7) は、next() 関数が基本クラス List にあることを認識できるべきではありませんか? そのようなすべての呼び出しの前に this-> を追加する必要があるのはなぜですか? 私は、clang 3.1 が同じ動作を示すことに気付いたので、c++ 標準にこの動作を必要とする何らかの要件があると思います。誰かがそれを正当化できますか?

4

3 に答える 3

63

問題は、テンプレートが 2 つのパスで処理されることです (標準によると、VS はそうではありません)。最初のパスでは、型置換の前に、テンプレート引数に依存しないすべてが検索され、チェックされます。型が置換されると、依存する名前は 2 番目のパスで解決されます。

ここで、最初のパスではnext、テンプレート引数に依存していることを示すものは何もないため、型置換の前に解決する必要があります。現在、基本型は現在のテンプレートのテンプレート引数でテンプレート化されているため、コンパイラはそれを調べることができません (一部の型に特化している可能性がありT、テンプレートをインスタンス化する型がわからないと、どの特殊化を行うべきかを知ることができません)。使用します。つまり、ベースは依存してTおり、知る前にチェックしていTます)。

追加のトリックは従属名にthis->変わります。これは、next2 番目のパスまでルックアップが遅延されることを意味します。TTList<T>


編集:上記の回答の文言に欠けている重要な詳細の1つは、第2フェーズのルックアップ(型置換後)が引数依存のルックアップ中に見つかった関数のみを追加することです。つまり、next関連付けられた名前空間内のフリー関数Tが見つかった場合、それはベースのメンバーであり、ADL on では表示されませんT

于 2012-05-17T16:05:21.197 に答える
14

次のように書く必要がありますthis->

this->next(item);

テンプレートベースから継承されたメンバーであるため、ここthis->の部分が必要です。エラーメッセージを注意深く読むと、それ自体が提案されています。next()

template_eg.cpp:18:25: 注: 依存ベースの宣言は'List<int>'非修飾ルックアップでは見つかりません
template_eg.cpp:18:25: 注:代わりに使用してください'this->next'

C++ での 2 フェーズの名前検索について説明したこの記事を読んでください。

于 2012-05-17T15:52:26.200 に答える
5

基本クラスがテンプレート インスタンスである場合、それが基本クラスの名前を参照していることを知る方法はありnextません。結局のところ、名前が存在する必要さえありません (特殊化について考えてみてください)。したがって、派生クラス テンプレートの先頭に、 または、または を追加して、実際にクラス メンバーであるコンパイラにアサートする必要があります。nextthis->List<T>::nextusing List<T>::next;

于 2012-05-17T15:51:54.130 に答える