98

私はしばらくclangで遊んでいましたが、テンプレートエラーから回復するためのヒントを提供するはずの「test / SemaTemplate /dependent-template-recover.cpp」(clangディストリビューション内)に出くわしました。

全体を簡単に最小限の例にまとめることができます。

template<typename T, typename U, int N> struct X {
    void f(T* t)
    {
        // expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}}
        t->f0<U>();
    }
};

clangによって生成されたエラーメッセージ:

tpl.cpp:6:13: error: use 'template' keyword to treat 'f0' as a dependent template name
         t->f0<U>();
            ^
            template 
1 error generated.

...しかし、template構文的に正しいコードにするために、キーワードをどこに挿入するのかを正確に理解するのに苦労していますか?

4

4 に答える 4

117

ISO C ++ 03 14.2 / 4:

メンバーテンプレートの特殊化の名前が。の後に表示される場合。または->postfix-expressionの場合、または修飾IDのnested-name-specifierの後に、postfix-expressionまたはqualified-idが明示的にtemplate-parameter(14.6.2)に依存する場合、メンバーのテンプレート名は次のようになります。キーワードテンプレートのプレフィックス。それ以外の場合、その名前は非テンプレートの名前であると見なされます。

Int->f0<U>(); f0<U>は、後に表示->され、テンプレートパラメータに明示的に依存するメンバーテンプレートの特殊化であるため、メンバーテンプレートの特殊化の前にキーワードUを付ける必要があります。template

したがって、に変更t->f0<U>()t->template f0<U>()ます。

于 2010-09-24T11:14:49.927 に答える
26

他の人が指摘したことに加えて、コンパイラが決心できず、両方の解釈がインスタンス化時に代替の有効なプログラムを生成する可能性があることに注意してください

#include <iostream>

template<typename T>
struct A {
  typedef int R();

  template<typename U>
  static U *f(int) { 
    return 0; 
  }

  static int f() { 
    return 0;
  }
};

template<typename T>
bool g() {
  A<T> a;
  return !(typename A<T>::R*)a.f<int()>(0);
}


int main() {
  std::cout << g<void>() << std::endl;
}

これは、前0を省略したとき、挿入したときに印刷されます。コードが何をするのかを理解するための演習として残しておきます。templatef<int()>1

于 2010-09-24T11:46:12.240 に答える
14

カレットがあるポイントの直前に挿入します。

template<typename T, typename U, int N> struct X {
     void f(T* t)
     {
        t->template f0<U>();
     }
};

編集:コンパイラのように考えると、このルールの理由がより明確になります。コンパイラーは通常、一度に1つまたは2つのトークンのみを先読みし、式の残りの部分を「先読み」しません。[編集:コメントを参照]キーワードの理由は、依存型の名前を示すためにキーワードが必要な理由と同じですtypename。「ねえ、これから表示する識別子は、テンプレートの名前ではなく、テンプレートの名前です。静的データメンバーの名前の後に小なり記号が続きます。」

于 2010-09-24T11:01:24.373 に答える
12

C++テンプレートからの抜粋

.templateコンストラクトtypenameの導入後、非常によく似た問題が発見されました。標準のビットセットタイプを使用した次の例を検討してください。

template<int N> 
void printBitset (std::bitset<N> const& bs) 
{ 
    std::cout << bs.template to_string<char,char_traits<char>, 
                                       allocator<char> >(); 
} 

この例の奇妙な構成は.templateです。テンプレートを余分に使用しないと、コンパイラは、後に続く小なりトークン(<)が実際には「小なり」ではなく、テンプレート引数リストの先頭であることを認識しません。これが問題になるのは、ピリオドの前の構成がテンプレートパラメータに依存している場合のみであることに注意してください。この例では、パラメーターbsはテンプレートパラメーターNに依存します。

結論として、.template表記(および-> templateなどの同様の表記)は、テンプレート内でのみ、テンプレートパラメーターに依存するものに従う場合にのみ使用する必要があります。

于 2010-09-24T11:11:58.873 に答える