2011-10-27 17 views
43

可能性の重複:
Officially, what is typename for?
Where and why do I have to put the template and typename keywords?"typename"キーワードはいつ必要ですか?

は、以下のコードを考えてみます。

template<class K> 
class C { 
    struct P {}; 
    vector<P> vec; 
    void f(); 
}; 

template<class K> void C<K>::f() { 
    typename vector<P>::iterator p = vec.begin(); 
} 

なぜ "型名" キーワードは、この例では必要なのか? 「typename」を指定する必要がある場合はありますか?

+0

http://stackoverflow.com/questions/610245/where-and-why-do- i-have-to-put-template-and-typ-name-on-dependent-names –

答えて

58

短い答え:という従属名のネストされた名前を参照するときはいつでも、パラメータが未知のテンプレートインスタンスの中に入れ子になっています。

長い答え:C++には、値、型、テンプレートという3つのエンティティがあります。それらのすべてが名前を持つことができます。名前だけではエンティティのどの階層であるかは分かりません。むしろ、名前の実体の性質に関する情報は、文脈から推論されなければならない。

この推論が不可能なときはいつでも、あなたはそれを指定する必要があります。

ここ
template <typename> struct Magic; // defined somewhere else 

template <typename T> struct A 
{ 
    static const int value = Magic<T>::gnarl; // assumed "value" 

    typedef typename Magic<T>::brugh my_type; // decreed "type" 
    //  ^^^^^^^^ 

    void foo() { 
    Magic<T>::template kwpq<T>(1, 'a', .5); // decreed "template" 
    //  ^^^^^^^^ 
    } 
}; 

言うことは不可能であるため、Magic<T>::gnarlMagic<T>::brughMagic<T>::kwpqは、expliciatedなければならなかった名前:Magicがテンプレートであるので、非常にのタイプのTに依存しています。たとえば、1次テンプレートとはまったく異なる特殊化があるかもしれません。

Magic<T>::gnarlを従属名にするのは、テンプレート定義内にあるという事実です。ここで、Tは不明です。 Magic<int>を使用していたのですが、コンパイラが知っているので、これは違うでしょう(約束します!)Magic<int>の完全な定義。

Magicのサンプル定義はここにあります。簡潔にするために特殊化の意味でconstexprを使用してください;古いコンパイラを使用している場合は、静的メンバー定数を変更してください古いスタイルの事前C++ 11の形に宣言)

template <typename T> struct Magic 
{ 
    static const T     gnarl; 
    typedef T &      brugh; 
    template <typename S> static void kwpq(int, char, double) { T x; } 
}; 
template <> struct Magic<signed char> 
{ 
    // note that `gnarl` is absent 
    static constexpr long double brugh = 0.25; // `brugh` is now a value 
    template <typename S> static int kwpq(int a, int b) { return a + b; } 
}; 

使用法:。

int main() 
{ 
    A<int> a; 
    a.foo(); 

    return Magic<signed char>::kwpq<float>(2, 3); // no disambiguation here! 
} 
+0

@Nils: 'const'は有効ではありませんC++。 –

+0

説明をありがとう。しかし、私は最後のことを理解できません。「Magic :: kwpq」という名前がテンプレートパラメータ「T」に依存しているため、これは* 2段階ルックアップ*の第2段階で解決されます。だから、コンパイラはその時にチェックすることができないはずです。なぜなら、名前がエンティティの*層に従って正しく使用されていれば、 'kwpq'がテンプレートか型式かどうかを判断できるのでしょうか? –

+0

@PaoloM:クラステンプレート「A」のメンバ関数の定義は、最初の段階で既に解析されていなければなりません。構文を理解するためには、曖昧さ回避が必要です。第2段階では、具象型 'T'のインスタンス化' Magic 'が実際に適切な署名を持つ関数である' kwpq'というメンバを持っていることを確認します。 (そして編集のおかげで!) –

7

型名キーワードが最初に完全なシンボルテーブルを有することなく、タイプ名は、テンプレートパラメータに依存するたびに必要とされる(したがって、コンパイラは識別子(タイプ又は)のセマンティクスを「知る」ことができパス)。


同じ意味で

ない、と少しあまり一般的で汎用テンプレートパラメータ使用した場合、唯一の型名キーワードも便利です。http://ideone.com/amImX

#include <string> 
#include <list> 
#include <vector> 

template <template <typename, typename> class Container, 
      template <typename> class Alloc = std::allocator> 
struct ContainerTests 
{ 
    typedef Container<int, Alloc<int> > IntContainer; 
    typedef Container<std::string, Alloc<int> > StringContainer; 
    // 
    void DoTests() 
    { 
     IntContainer ints; 
     StringContainer strings; 
     // ... etc 
    } 
}; 

int main() 
{ 
    ContainerTests<std::vector> t1; 
    ContainerTests<std::list> t2; 

    t1.DoTests(); 
    t2.DoTests(); 
} 
+0

私は決してabを知りませんでした前に "孤独なtypename"を出して、それはクールです! –

10

typenameキーワードは、理由は必要とされていますiteratorPの依存型です。コンパイラは、iteratorが値または型を参照しているかどうか推測できません。したがって、typenameが返されない限り、その値が仮定されます。テンプレートの引数に依存する型がある場合は常に、型または値が有効であるコンテキストで必要です。例えば、基本クラスはtypenameとしては不要です。基本クラスは型でなければならないからです。

同じサブジェクトには、依存関係の名前が値ではなくテンプレート関数であることをコンパイラに知らせるために使用されるキーワードtemplateがあります。

関連する問題