2010-12-17 41 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