为什么编译器不能区分typedef和non-typedef?

时间:2010-12-17 16:13:22

标签: c++ compiler-errors 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 {}

错误消失了;程序编译正确。 (想想我在这些例子中没有返回任何内容的事实;这与示例无关。)

什么是编译器解释错误版本阻止第二版本没有成功编译,我该如何解决这个问题?

更多代码

我正在使用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);
}

7 个答案:

答案 0 :(得分:2)

实例化cbegin()时得到的错误是你将(const) this传递给构造函数,该构造函数接受一个非const指针到List。

基本上我怀疑这个想法是否有效。

 typedef const Iter_   const_iterator;

答案 1 :(得分: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_时,您的文件中确实存在一个实际的重复定义。您能否给我们一个完整的代码示例,但无法使用错误消息进行编译?

编辑: 我再试一次你的更好的例子。它修复了很多错误(缺少函数说明和缺少大小_)。

之后,cbegin编译正常而cend没有,因为您编写了typename const List<T>::Iter_ List<T>::cend() const而不是const typename List<T>::Iter_ List<T>::cend() const(const不是typename限定的事物的一部分1}})。

如果cbegin确实是产生错误的那个,那对我来说听起来像编译器错误。

答案 2 :(得分: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);
}

请检查您是否正确标记了代码。

答案 3 :(得分:1)

如果我进行以下更改,我可以在VS2008中编译您的代码:
template <typename T>
typename const List<T>::const_iterator List<T>::cbegin() const
我不知道为什么额外的const应该有所不同,但我敢打赌有人会这样做。

答案 4 :(得分:1)

编辑:

多奇怪啊我甚至使用自动类型演绎来获得正确的返回类型,它仍然拒绝我的代码。

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

当然,你发布的代码有很多你定义但没有声明的函数,比如operator =,constructors,destructor,这些函数给我带来了错误。如果内联实现,它也可以完美正常运行。这对我来说就像一个编译器错误。

答案 5 :(得分: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编译器中的一个错误。

答案 6 :(得分: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;
}

如果没有,你有一个编译器错误的小演示!