Why can't the compiler distinguish between typedef and non-typedef?

Sorry for the long headline.

I have a typedef in the List class:

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 definition outside the class, but inside the header file.

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

This causes error C2373: Redefinition; different type modifiers Redefinition; different type modifiers

I rewrote this function:

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

and the error has disappeared; The program compiles correctly. (think that I will not return anything in these examples, this is not relevant to this example.)

What is a compiler interpreter with an erroneous version that prevents successful compilation, which is not in the second version, and how can I fix it?

More code

I am using VS2008

Example code (more complete) that I am programming now:

 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); } 
+4
source share
7 answers

The error that occurs when creating an instance of cbegin() is that you pass (const) this constructor that accepts a non-content pointer to a list.

Basically, I doubt this idea works well.

  typedef const Iter_ const_iterator; 
+2
source

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

just compiles with gcc 4.2.2 (which I admit to being old).

However, this is similar to the actual duplicate definition in your files that you deleted when you changed the type to Iter_ . Could you give us a complete example of code that does not compile with the error message?

EDIT: I tried again with your great example. It had a lot of errors (there were no functions of decartation and missing size_), which I corrected.

After that, cbegin compiled while cend did not, 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 that matters with typename ).

If cbegin really is the one that generates the error, it sounds like a compiler error to me.

+1
source

It:

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

compiles with g ++. But this is not so:

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

Could you make sure that you entered your code correctly.

+1
source

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 this extra const should matter, but I bet someone is doing it.

+1
source

Edit:

How strange. I even used automatic type inference 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 published code has a bunch of functions that you defined but did not declare, for example operator =, constructors, destructor, which threw errors to me. It also works great if built-in is implemented. This stinks like a compiler error for me.

+1
source

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 changed the last line to

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

it will not compile. Mark gave an excellent explanation for this, typename List<T>::Iter is the only thing that cannot be separated by inserting modifiers of a random type inside. This also works great:

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

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

+1
source

Try to reduce this to the maximum possible. Does MSVC 2008 compile this file?

 template <typename T> class L { public: class I {}; typedef const IC; C f() const; }; template <typename T> typename L<T>::C L<T>::f() const { return C(); } int main() { L<int> x; xf(); return 0; } 

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

+1
source

Source: https://habr.com/ru/post/1332525/


All Articles