为什么编译器不能区分 typedef 和非 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:重新定义;不同的类型修饰符
我像这样重写了函数:
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
实例化
cbegin()
时出现的错误是,您将(const) this
传递给构造函数,该构造函数采用指向 List 的非常量指针。基本上我怀疑这个想法是否有效。
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.
这:
用 g++ 编译。但这不是:
您能否检查一下您是否正确标记了代码。
This:
compiles with g++. But this doesn't:
Can you please check that you have labelled your code correctly.
如果我进行以下更改,我可以在 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.
编辑:
多么奇怪啊。我什至使用自动类型推导来肯定获得正确的返回类型,但它仍然拒绝我的代码。
当然,您发布的代码有一堆您定义但未声明的函数,例如operator=、构造函数、析构函数,这给我带来了错误。如果内联实现,它也可以完美正确地运行。这对我来说就像一个编译器错误。
Edit:
How very strange. I even used automatic type deduction to definitely get the correct return type, and it still rejected my code.
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.
代码:
使用 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:
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 whilecend
didn't, because you wrotetypename const List<T>::Iter_ List<T>::cend() const
instead ofconst typename List<T>::Iter_ List<T>::cend() const
(const is NOT part of the thing qualified withtypename
).If
cbegin
really is the one generating an error it sounds like a compiler bug to me.在 GCC 4.5.0 (MinGW) 上进行测试,以下代码可以正常编译:
如果我将最后一行更改为
它将无法编译。 Mark 对此给出了很好的解释,
typename List::Iter
是一个单独的东西,不应该通过在其中插入随机类型修饰符来分隔。这也很好用:GCC 行为对我来说非常有意义,所以我认为这是 MSVC 编译器中的一个错误。
Testing this on GCC 4.5.0 (MinGW), the following code compiles fine:
If I change the last line to
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:GCC behavior makes perfect sense to me, so I think this is a bug in the MSVC compiler.
让我们尝试将其简化为尽可能简单的。 MSVC 2008 是否编译此文件?
如果没有,您将看到一个编译器错误的小演示!
Let's try reducing this to the simplest possible. Does MSVC 2008 compile this file?
If not, you have a small demonstration of a compiler bug!