I have a task for which you need to make your iterator, and then pass an iterator test for its performance. But I had a problem with checking the constant iterator. The iterator itself looks like this:

class const_iterator { public: typedef const_iterator self_type; typedef const std::pair<Key, mapped_type> value_type; typedef const value_type& reference; typedef const value_type* pointer; typedef std::forward_iterator_tag iterator_category; typedef int difference_type; //constructors const_iterator() { curr = nullptr; currPair = new value_type; printf("111\n"); } const_iterator(Tree_ &n) { printf("2"); curr = &n; currPair = new value_type; *currPair = std::make_pair(curr->key, curr->getValue()); } const_iterator(const self_type& other) { curr = other.curr; currPair = new value_type; *currPair = *other.currPair; } const_iterator(const std::pair<Key, mapped_type>& other) { curr = other.curr; currPair = other.currPair; } //operators //prefix increment self_type& operator++() { //сравни старое значение и новое if (currPair->second != curr->getValue()) curr->setValue(currPair->second); curr = successor(); // point to next node if (curr) *currPair = std::make_pair(curr->key, curr->getValue()); return *this; } // postfix increment (it++) self_type operator++(int) { self_type old = *this; ++(*this); return old; } //reference const reference operator*() const { return *currPair; } //pointer const pointer operator->() { return currPair; } // Inequality test operator bool operator!=(self_type const & other) const { return this->curr != other.curr; } // Dereference operator bool operator==(self_type const & other) const { return this->curr == other.curr; } operator iterator() const { return iterator(); } private: pointer currPair; Tree_* curr; //Successor Tree_* successor() { if (curr) if (curr->right != 0) { curr = curr->right; while (curr->left != 0) curr = curr->left; } else { Tree_* y = curr->parent; if (y == nullptr) return nullptr; while (curr == y->right) { curr = y; y = y->parent; if (y == nullptr) return nullptr; } if (curr->right != y) curr = y; } return curr; } }; 

check is stuck on the moment

 using mp_it1 = mp::const_iterator; mp_it1 tmp1; static_assert(std::is_const<decltype(*tmp1)>::value, "returned value by dereferencing iterator is not const"); 

The compiler tells me:

Line Error C2338 returned value by dereferencing iterator is not const

Could you tell me what is wrong with my iterator, and how to fix it?

  • Iterators did not implement, but the logic suggests: if it is a const iterator, then it should have access to the tree by a const pointer. Similarly, mapped_type must also be const. Correct if you made a mistake - int3
  • I tried to translate the tree into a const, but there was no result. - Demolver 4:08 pm

1 answer 1

Two points:

  typedef std::pair<Key, mapped_type> value_type; typedef value_type& reference; //reference reference operator*() const { return *currPair; } 

your value_type not a constant expression, so in this form you return a non-constant link (in the second method, similarly, but a non-constant pointer is returned), and therefore the static_assert works. In fact, you would just add a const before the type in these methods (it is added below):

  //reference const // имеем: const std::pair<Key, mapped_type>& reference operator*() const { return *currPair; } //pointer const // имеем: const std::pair<Key, mapped_type>* pointer operator->() const // этот const тоже добавлен - дабы не нарушать семантику { // и нафига вы так усложняете? //return &(operator*()); // сделайте просто: return currPair; } 

But it would be more correct to leave the types of methods as they are (except for const , which adds constancy to the method of obtaining a pointer - it is needed), and declare the type synonyms for the pointer and the reference with const :

  typedef const value_type& reference; typedef const value_type* pointer; 

Well, successor better to do private.

And also, for good, you need to add another typedef to determine the category of the iterator: typedef ... iterator_category; and for difference_type , details . It is necessary that this could work with your iterator.

UPD: yes, overlooked, the check itself is also incorrect, see: http://en.cppreference.com/w/cpp/types/is_const , in the examples - your case is the last. Without going into details, but you need to remove the link from the type:

static_assert (std :: is_const :: type> :: value, "returned value by dereferencing iterator is not const");

In short, is_const checks the constancy of the expression itself, and not the value to which it refers or indicates. You can see it on the signs:

 const int* ptr0; int* const ptr1; const int* const ptr2; 

The first is the UNCONSTANT pointer (that is, its value can be changed and it will point to another block of memory) to CONSTANT data (but the data on this pointer cannot be changed). Since the value of the pointer itself can be changed, is_const will return false here. Although the semantics of your use is exactly what you need: to prohibit changing data.

The second is a CONSTANT pointer to UNCONSTANT data. Those. it is impossible to change the pointer itself, only initializing once, but please refer to the data on it. is_const for him is true .

The third is to put it all together: neither the value of the pointer nor the data on it can be changed. Naturally, is_const for him is true .

How to figure it out is a simple mnemonic rule: qualifiers before * refer to the data on the pointer, after * - to the pointer itself. It follows from this that these records are identical:

 const int* a; int const* b; 

With links a little zamorocheny. In general, the rules above (mentally) are applicable to them, because References are sugar over pointers and cannot be changed. Those. record:

 int & const a = b; 

simply does not make sense, because to make it so that a would refer to another object, we simply can not. Therefore, such a record, if my memory serves me, is unacceptable to use. Accordingly, only constancy management is allowed for the stored data:

 const int& a = c; int const& b = c; 

But is_const works with links in the same style as with pointers, which is why it returns false for the expressions above, although, like, const after & is already implied.

That is why, in order to check the constancy of data access by reference or pointer, you need to remove the link or pointer from the type and check the resulting type:

 std::remove_reference<...>::type; std::remove_pointer<...>::type; 

Check: http://ideone.com/uZzwVp , in the same place, read the comments with the prefix HTRD:

  • I did everything adhering to the advice, but unfortunately the test still doesn’t pass, can this be a problem with the VS2014 compiler? - Demolver
  • No, I looked through the test a little. Completed the answer. - Monah Tuk