2009-07-14 22 views
13
template<class T> 
class Set 
{ 
public: 
    void insert(const T& item); 
    void remove(const T& item); 
private: 
    std::list<T> rep; 
} 

template<typename T> 
void Set<T>::remove(const T& item) 
{ 
    typename std::list<T>::iterator it = // question here 
    std::find(rep.begin(),rep.end(),itme); 
    if(it!=rep.end()) rep.erase(it); 

} 

なぜremove()の型名が必要なのですか?ここでtypenameが必要なのはなぜですか?

+0

あなたが話している行がtypename std :: list :: iterator it = std :: find(rep.begin()、rep.end()、itme)であることを明確にするために、おそらく編集します。私はそれがあなたの意図だと思っているからです。 – aem

答えて

18

一般的に、C++が原因不幸構文typenameを必要とする[*]それは言って、非ローカル情報なしでは不可能その、Cから継承する - 例えば - A * B;Aか名前タイプ(INこれは、Bの宣言である)、そうでない場合(この場合、これは乗算式で、Aから可能です。非ローカル情報なしですべてのことが分かるので、 operator*は何か変なことをするためにオーバーロードします;-)。

ほとんどの場合、コンパイラは非ローカル情報を必要とします(残念なことにシンタックスは低レベルのパーサーがシンボルテーブル情報を保持する上位層からのフィードバックを必要とします)...しかしテンプレートはありません(一般的ではありませんが、を特殊化して::iteratorがタイプ名にならないようにすることは技術的に違法かもしれませんが;-)。

[*]私の意見だけでなく、Ken Thompson氏とRob Pikes氏(私の同僚)は、新しいプログラミング言語の設計と実装に忙しいと思っています。ほとんどC言語のように、Cの構文設計エラーを繰り返すことはありません。新しい言語(例えば、古いPascalのような)です。構文では、タイプを指定しなければならない識別子を区別するのに十分です;-)。

+1

イテレータは、潜在的に静的メンバ変数である可能性があります。そして、デフォルトでは、コンパイラはそれを前提としていました。したがって、コンパイラのエラーです。 –

+0

私はそれが "B ++"と呼ばれているかどうかを確認することは商業的機密性の深刻な違反でしょうか? ;-) –

+0

これを死者に戻して申し訳ありませんが、8年後、私は、プログラミング言語について何か情報を開示することができるかどうかについてさらに興味があるかどうか不思議です。私は私の呼吸を保持していませんが。 – Cebtenzzre

0

一般に、関数定義の完全/部分テンプレート指定を定義できるので、クラス宣言と関数定義のtypename/class Tの両方が必要だと思います。つまりあなたはint、文字列のためにあなたのremove関数を特化することができます。したがって、この場合、コンパイラに "これはどのタイプの汎用テンプレートでもあります"と伝え、その後、整数だけに指定された同じ関数を定義することになります。

+0

ああ、この解答は無効です、申し訳ありません! – DeusAduro

12

あなたはstd::list<T>::iteratorで使用typenameの話をしている場合:

型名はiteratorがクラスstd::list<T>内で定義されたタイプであることを明確にするために使用されています。 typenameがないと、std::list<T>::iteratorは静的メンバーとみなされます。 typenameは、テンプレートパラメータに依存する名前が型の場合に使用されます。

+0

+1素晴らしい説明! – AraK

1

'it'の宣言ではtypenameが必要です。そうでなければ、コンパイラは式ではなく型宣言であることを知らないからです。

this pageによると、タイプを参照し、テンプレートパラメータに依存する修飾名がある場合は、キーワードtypenameを使用します。

関連する問題