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

发布于 2024-10-08 03:21:23 字数 3438 浏览 0 评论 0原文

抱歉标题太长了。

我在类 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:重新定义;不同的类型修饰符

我像这样重写了函数:

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);
}

Sorry for the long title.

I have a typedef in a class List:

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

and the definition outside of the class, but inside the header file.

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

This produces the error C2373: Redefinition; different type modifiers

I rewrote the function like so:

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

and the error is gone; the program compiles correctly. (think away the fact I'm not returning anything in these examples; it's irrelevant to the example.)

What is the compiler interpreting with the erroneous version that prevents successful compilation that the second version does not, and how can I remedy this?

More Code

I'm using VS2008

The (fuller) code example I'm currently programming:

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);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

完美的未来在梦里 2024-10-15 03:21:23

实例化 cbegin() 时出现的错误是,您将 (const) this 传递给构造函数,该构造函数采用指向 List 的非常量指针。

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

 typedef const Iter_   const_iterator;

The error I get when instantiating cbegin() is that you are passing (const) this to the constructor which takes a non-const pointer to the List.

Basically I doubt this idea works that well.

 typedef const Iter_   const_iterator;
单挑你×的.吻 2024-10-15 03:21:23

这:

// 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);
}

您能否检查一下您是否正确标记了代码。

This:

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

compiles with g++. But this doesn't:

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

Can you please check that you have labelled your code correctly.

睫毛上残留的泪 2024-10-15 03:21:23

如果我进行以下更改,我可以在 VS2008 中编译您的代码:
模板
typename const List::const_iterator List::cbegin() const
我不知道为什么额外的 const 会产生影响,但我敢打赌有人会这样做。

I can compile your code in VS2008 if I make the following change:
template <typename T>
typename const List<T>::const_iterator List<T>::cbegin() const
I don't know why that extra const should make the difference, but I'll bet someone does.

吝吻 2024-10-15 03:21:23

编辑:

多么奇怪啊。我什至使用自动类型推导来肯定获得正确的返回类型,但它仍然拒绝我的代码。

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

当然,您发布的代码有一堆您定义但未声明的函数,例如operator=、构造函数、析构函数,这给我带来了错误。如果内联实现,它也可以完美正确地运行。这对我来说就像一个编译器错误。

Edit:

How very strange. I even used automatic type deduction to definitely get the correct return type, and it still rejected my code.

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

Of course, your posted code has a bunch of functions that you defined but didn't declare, like operator=, constructors, destructor, which threw errors for me. It also functions perfectly correctly if implemented inline. This stinks like a compiler bug to me.

友谊不毕业 2024-10-15 03:21:23

代码:

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_ 时,您删除了该定义。您能否给我们一个完整的代码示例,该示例无法编译并出现错误消息?

编辑:
我再次尝试用你的更大的例子。我修复了它的大量错误(缺少函数声明和缺少 size_)。

之后,cbegin编译得很好,而cend则不然,因为你写了typename const List::Iter_ List::cend() const 而不是 const typename List::Iter_ List::cend() const (const 不是用 typename)。

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

The code:

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

compiles just fine with gcc 4.2.2 (which I admit is old).

However it sounds like there's an actual duplicate definition in your file(s) that you removed when you changed the type to Iter_ instead. Could you give us a full code example that fails to compile with the error message?

EDIT:
I tried again with your bigger example. It had a ton of errors (missing function delcarations and missing size_) that I fixed.

After that, cbegin compiled fine while cend didn't, because you wrote typename const List<T>::Iter_ List<T>::cend() const instead of const typename List<T>::Iter_ List<T>::cend() const (const is NOT part of the thing qualified with typename).

If cbegin really is the one generating an error it sounds like a compiler bug to me.

乙白 2024-10-15 03:21:23

在 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::Iter 是一个单独的东西,不应该通过在其中插入随机类型修饰符来分隔。这也很好用:

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

GCC 行为对我来说非常有意义,所以我认为这是 MSVC 编译器中的一个错误。

Testing this on GCC 4.5.0 (MinGW), the following code compiles fine:

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

If I change the last line to

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

it won't compile. Mark gave an excellent explanation for this, typename List<T>::Iter is a single thing that shouldn't be separated by inserting random type modifiers inside. This also works fine:

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

GCC behavior makes perfect sense to me, so I think this is a bug in the MSVC compiler.

栖竹 2024-10-15 03:21:23

让我们尝试将其简化为尽可能简单的。 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;
}

如果没有,您将看到一个编译器错误的小演示!

Let's try reducing this to the simplest possible. Does MSVC 2008 compile this file?

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

If not, you have a small demonstration of a compiler bug!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文