2010-12-17 62 views
4

對不起,長標題。爲什麼編譯器不能區分typedef和non-typedef?

我有一個類List一個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 {} 

和誤差消失;該程序編譯正確。 (想想這些事例中我沒有返回任何東西;這與示例無關)

什麼是編譯器解釋錯誤的版本,阻止成功編譯第二個版本沒有,以及我怎樣才能補救這個?

更多的代碼

我使用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 2010-12-17 16:31:04

+1

comeau編譯它就好了(除了'typename const List :: Iter_ etc ...'應該是'const typename etc ...') – lijie 2010-12-17 16:33:14

+0

@atzz:我已經添加了額外的代碼。 – IAE 2010-12-17 16:33:41

回答

2

實例化cbegin()時出現的錯誤是您將(const) this傳遞給構造函數,該構造函數將非const指針指向List。

基本上我懷疑這個想法是否適用。

typedef const Iter_ const_iterator; 
+1

+1:實際上,這不是** const_iterator是什麼。它被實現爲一個不同的類型,因爲它需要可變操作,比如'operator ++'。 – 2010-12-17 17:40:33

+0

感謝您的澄清!當我將函數定義更改爲可行的函數時(我在V​​S2008上),我遇到了您提到的錯誤。 – IAE 2010-12-17 17:56:58

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_而不是刪除文件(S)的實際重複定義。你能給我們一個完整的代碼示例,無法編譯錯誤消息嗎?

編輯: 我與你更大的例子再次嘗試。它有很多我修復的錯誤(缺少函數刪除和缺少size_)。

之後,cbegin編譯細而cend沒有,因爲你寫typename const List<T>::Iter_ List<T>::cend() const,而不是const typename List<T>::Iter_ List<T>::cend() const(常量不是的東西合格與typename部分)。

如果cbegin真的是一個產生這聽起來像一個編譯器錯誤給我的錯誤。

+0

我已經添加了我正在使用的代碼。 – IAE 2010-12-17 16:30:42

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 2010-12-17 16:44:52

1

我可以編譯VS2008中的代碼,如果我做了以下變化:
template <typename T>
typename const List<T>::const_iterator List<T>::cbegin() const
我不知道爲什麼額外的常量應該賺取差價,但我敢打賭,有人做。

+0

這裏不應該有所作爲。這聽起來像一個編譯器錯誤。 – aschepler 2010-12-17 18:00:51

1

編輯:

多麼奇怪。我甚至使用自動類型演繹來獲得正確的返回類型,並且仍然拒絕了我的代碼。

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

當然,你貼的代碼有一幫您定義但沒有申報的,像運營商=,構造函數,析構函數,該扔的錯誤,我的功能。如果在線實施,它也可以正常工作。這聽起來像是一個編譯器bug。

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 {} 

它不會編譯。馬克給出了一個很好的解釋,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; 
} 

如果不是的話,你有一個編譯器bug的小示例!

+0

不編譯;但我想你已經試過了?感謝這個例子。 – IAE 2010-12-17 18:31:31

+0

嗯,我沒有MSVC 2008.我用我的g ++版本試過了,它工作。 – aschepler 2010-12-17 18:42:01