2010-12-17 16 views
4

長いタイトルを残して申し訳ありません。コンパイラがtypedefとnon-typedefを区別できないのはなぜですか?

私は、クラスリストのtypedefを持っている:

template <typename T> 
class List { 
    // Think of a class Iter_ with ListElem *pCurrentPos and List *pList 
    typedef const Iter_ const_iterator; 

    const_iterator cbegin() const; 
}; 

とクラスの外ではなく、ヘッダファイル内の定義を。

template <typename T> 
typename List<T>::const_iterator List<T>::cbegin() const {} 

これはエラーC2373生成します。私はそうのような機能を書き直しRedefinition; different type modifiers

を:

template <typename T> 
const typename List<T>::Iter_ List<T>::cbegin() const {} 

とエラーがなくなっています。プログラムは正しくコンパイルされます。

2番目のバージョンでは成功しないコンパイルを妨げる誤ったバージョンのコンパイラはどのようなものですか。どのようにすればよいでしょうか?この例では、これを改善する?

私は現在、プログラミングてるVS2008

(フラー)のコード例を使用してい

もっとコード:

template <typename T> 
class List 
{ 
public: 
    // Forward declaration. 
    class Iter_; 

private: 
    ///////////////////////////////////////////////////////// 
    // ListElem 
    ///////////////////////////////////////////////////////// 
    struct ListElem 
    { 
     T data; 
     // Doubly-linked list. 
     ListElem *next; 
     ListElem *prev; 
    }; 

    class ListException {}; 

    //////////////////////////////////////////////////////// 
    // List Members 
    //////////////////////////////////////////////////////// 
    // Point to first elem. 
    ListElem *head_; 
    // Point to last elem. 
    ListElem *tail_; 

public: 
    ////////////////////////////////////////////////////////// 
    // Typedefs 
    ////////////////////////////////////////////////////////// 
    typedef  Iter_ iterator; 
    typedef const Iter_ const_iterator; 

    ////////////////////////////////////////////////////////// 
    // Iterator class 
    ////////////////////////////////////////////////////////// 
    class Iter_ 
    { 
    public: 
     Iter_(ListElem *pCurr, List *pList) 
      : pCurr_(pCurr), pList_(pList) 
     {  } 

     T& operator*() 
     { 
      if(*this == pList_->end()) 
       throw ListException(); 
      else 
       return pCurr_->data; 
     } 

    private: 
     ListElem *pCurr_; 
     List  *pList_; 
    }; 

iterator begin(); 
iterator end(); 

const_iterator cbegin() const; 
const_iterator cend() const; 
}; 

template <typename T> 
List<T>::List() 
    : head_(0), tail_(0), size_(0) 
{ } 

template <typename T> 
List<T>::~List() 
{ 
    //this->clear(); 
} 

template <typename T> 
List<T>::List(List const& other) 
    : size_(other.size_) 
{ 
    //this->clone(other); 
} 

template <typename T> 
List<T>& List<T>::operator=(List const& other) 
{ 
    size_ = other.size_; 
    //this->clone(other); 
} 

// Compiles ok 
template <typename T> 
typename List<T>::iterator List<T>::begin() 
{ 
    if(!head_) 
     head_ = new ListElem(); 
    return iterator(head_, this); 
} 

// Compiles ok 
template <typename T> 
typename List<T>::iterator List<T>::end() 
{ 
    return iterator(tail_, this); 
} 

// Compiler error 
template <typename T> 
typename List<T>::const_iterator List<T>::cbegin() const 
{ 
    return const_iterator(head_, this); 
} 

// Compiles ok 
template <typename T> 
typename const List<T>::Iter_ List<T>::cend() const 
{ 
    return const_iterator(tail_, this); 
} 
+0

ここで(どのように) 'Iter_'が定義されていますか? – atzz

+1

comeauはそれをちゃんとコンパイルします( 'typename const List :: Iter_ etc ...' 'const typename etc ...')。 – lijie

+0

@atzz:追加コードを追加しました。 – IAE

答えて

2

cbegin()をインスタンス化すると、(const) thisをコンストラクタに渡して、リストに非constポインタを渡すというエラーが発生します。

基本的に私はこの考えがうまく機能するのか疑問です。

typedef const Iter_ const_iterator; 
+1

+1:確かに、それは 'const_iterator'が何であるかではなく**です**。これは 'operator ++ 'のような変更可能な操作が必要なため、異なる型として実装されています。 –

+0

説明をありがとう!私は関数定義を実行可能なもの(VS2008の私のために)に変更したときにあなたが言及したエラーにぶち当たっていました。 – IAE

1

コード:

class Iter_ 
{ 
}; 

template <typename T> 
class List { 
public: 
    // Think of a class Iter_ with ListElem *pCurrentPos and List *pList 
    typedef const Iter_ const_iterator; 

    const_iterator cbegin() const; 
}; 

template <typename T> 
typename List<T>::const_iterator List<T>::cbegin() const {} 

int main() 
{ 
    List<int> foo; 

    List<int>::const_iterator iter = foo.cbegin(); 

    return 0; 
} 

gcc 4.2.2でうまくコンパイルします(私は古いと認めます)。

しかし、タイプをIter_に変更したときに削除したファイルには、実際に重複する定義があるようです。エラーメッセージでコンパイルできない完全なコード例を教えてください。

EDIT: あなたの大きな例でもう一度試しました。それは私が修正した1トンのエラー(関数の欠落と欠落したサイズ_)がありました。 cendはなかったが、あなたが(定数がtypenameで修飾物の一部ではない)typename const List<T>::Iter_ List<T>::cend() constの代わりconst typename List<T>::Iter_ List<T>::cend() constを書いたので、その後

cbeginは、罰金コンパイル。

cbeginが実際にはエラーを生成するものであれば、コンパイラのバグのように聞こえるかもしれません。

+0

を参照してください。使用しているコードを追加しました。 – IAE

1

この:

// Compiler error 
template <typename T> 
typename List<T>::const_iterator List<T>::cbegin() const 
{ 
    return const_iterator(head_, this); 
} 

は、G ++でコンパイルします。しかし、これはしません:

// Compiles ok 
template <typename T> 
typename const List<T>::Iter_ List<T>::cend() const 
{ 
    return const_iterator(tail_, this); 
} 

はあなたが正しくあなたのコードのラベルが付いていることを確認してくださいすることができます。

+0

はい、あります。私はVS2008を使用しているので、その違いを引き起こす可能性があります。 – IAE

1

私は次のように変更します場合はVS2008でコードをコンパイルすることができます
template <typename T>
typename const List<T>::const_iterator List<T>::cbegin() const
をその余分のconstは違いを作る必要があり、なぜ私は知らないが、私は誰が行う賭けます。

+0

ここで違いはありません。これはコンパイラのバグのように聞こえる。 – aschepler

1

編集:

どのように非常に奇妙ですか。私は正しいタイプの戻り値を得るために自動型の控除を使用していましたが、それでも私のコードは拒否されました。もちろん

template <typename T> 
decltype(List<T>().cbegin()) List<T>::cbegin() const 
{ 
    return const_iterator(head_, this); 
} 

、あなたの投稿コードを使用すると、定義された関数の束を持っていますが、私のためにエラーを投げた演算子=、コンストラクタ、デストラクタ、同じように、宣言していませんでした。インラインで実装されている場合は、完全に正しく機能します。これはコンパイラのバグのようなものです。

1

テストこれは、GCC 4.5.0(MinGWの)上で、次のコードは、罰金コンパイル:

template <typename T> 
class List { 
    public: 
    class Iter_ {}; 
    // Think of a class Iter_ with ListElem *pCurrentPos and List *pList 
    typedef const Iter_ const_iterator; 

    const_iterator cbegin() const; 
    const_iterator cend() const; 
}; 
template <typename T> 
typename List<T>::const_iterator List<T>::cbegin() const {} 
template <typename T> 
const typename List<T>::Iter_ List<T>::cend() const {} 

私は

typename const List<T>::Iter_ List<T>::cend() const {} 

への最後の行を変更した場合、それはコンパイルされません。 Markはこれについて優れた説明を与えました。typename List<T>::Iterは、内部にランダム型修飾子を挿入して区切ってはならない単一のものです。

typename List<T>::Iter_ const List<T>::cend() const {} 

GCCの振る舞いは私に完璧な理にかなっているので、私は、これはMSVCコンパイラのバグだと思う:これも正常に動作します。

1

これをできるだけ簡単に減らしてみましょう。 MSVC 2008はこのファイルをコンパイルしますか?

template <typename T> class L { 
public: 
    class I {}; 
    typedef const I C; 
    C f() const; 
}; 

template <typename T> typename L<T>::C L<T>::f() const { return C(); } 

int main() { 
    L<int> x; 
    x.f(); 
    return 0; 
} 

そうでなければ、コンパイラのバグの小さなデモンストレーションがあります。

+0

コンパイルされません。しかし、私はあなたがすでにそれを試みたと思いますか?この例をありがとう。 – IAE

+0

さて、私はMSVC 2008を持っていません。私はg ++バージョンで試してみました。 – aschepler

関連する問題