GNOME Bugzilla – Bug 543671
Notebook::PageList::const_iterator operator!= does not work (with gcc 4.3.1)
Last modified: 2010-10-19 17:10:18 UTC
The following code does not work with gtkmm 2.12.7 and gcc 4.3.1 const Notebook::PageList& list = notebook->pages(); Notebook::PageList::const_iterator it = list.begin(); for ( ; it != list.end(); ++it ) { ... } Compilation fails on containers.h:340 bool operator!=(const Self& src) const { return T_Base::operator!=(src); } with the following error from gcc: /usr/include/glibmm-2.4/glibmm/containers.h|340|error: 'operator!=' is not a member of 'Gtk::Notebook_Helpers::PageIterator'| It works fine when the const_iterator is replaced with a plain iterator.
Well, const_iterator doesn't seem to be the only iterator type that's not working: reverse_iterator and const_reverse_iterato produce the same error.
This seems to be because the PageList has the operator== and operator != as separate functions rather than member functions: /** @relates Gtk::Notebook_Helpers::PageIterator */ inline bool operator==(const PageIterator& lhs, const PageIterator& rhs) { return lhs.equal(rhs); } /** @relates Gtk::Notebook_Helpers::PageIterator */ inline bool operator!=(const PageIterator& lhs, const PageIterator& rhs) { return !lhs.equal(rhs); } I forget why that's generally considered a good thing. I suppose we could make the member operator functions separate functions in glibmm/containers.h and make the code expect that. Thoughts?
Created attachment 115815 [details] notebook_pages_const_iter_test.cc An actual test case.
non-member operators are usually considered a good thing because it's the only way to support implicit type conversions for both operands. It helps to replace containers.h:339 and 340: bool operator==(const Self& src) const { return T_Base::operator==(src); } bool operator!=(const Self& src) const { return T_Base::operator!=(src); } with the following: bool operator==(const Self& src) const { return *this == src } bool operator!=(const Self& src) const { return *this != src }
Wouldn't that be an infinite loop? Could you try that and provide a patch, please?
Yes, you're right it's an infinite loop. Why are those operators defined there anyhow? If I just remove the operators from class List_ConstIterator then the correct non-member operator is invoked. Does this extra indirection have any benefit?
I guess they are there because there would be no == or != without them, because there is no separate static == or !- operator overloading for those types (though there are for the notebook stuff). I guess it wouldn't be too bad to change them to non-member operator overloads in containers.h. I guess that not many people are overriding them, call these member methods explicitly.
Do you mean to define a non-member operator for List_ConstIterator? How would that help? The compiler would then still select this operator over the one defined for const PageIterator&
Yeah. Maybe we can specify the exact operator= by casting to the specific type? But maybe that would still sometimes result in an infinite loop.
Hm.. casting to the concrete type wouldn't work in all cases, for example when the operator is defined in another base class (ok this also wouldn't work with the current solution) Wouldn't be the best solution to make all operators in all the classes non-member operators and remove the operators from containers.h? That way the compiler could always select the best match via overload resolution and implicit conversions. It would also not break existing code. And subclasses could still provide their own version of the operator by just providing an operator with the concrete type of that subclass. Or am I missing something?
> Wouldn't be the best solution to make all operators in all the classes > non-member operators and remove the operators from containers.h? Remove the operators? That would definitely break API. Of course, I'd be very happy if you tried creating a patch to test your idea.
Created attachment 172705 [details] Source code for Gtk::Notebook test case In comments 4, 5, and 6 we learn that it's not possible to replace: bool operator==(const Self& src) const { return T_Base::operator==(src); } bool operator!=(const Self& src) const { return T_Base::operator!=(src); } with the following: bool operator==(const Self& src) const { return *this == src } bool operator!=(const Self& src) const { return *this != src } But it's possible to replace with: bool operator==(const Self& src) const { return *static_cast<const T_Base*>(this) == src; } bool operator!=(const Self& src) const { return *static_cast<const T_Base*>(this) != src; } Then operator== and operator!= can be either member functions in PageIterator, or they can be non-member functions. See the attached test case, with comments at the beginning of the attachment. I've seen in the Git repository that Gtk::Notebook has been considerably modified since gtkmm v2.20.3. That's what's included in Ubuntu 10.10, which I'm using. In branch gtkmm-2-22 PageIterator is marked deprecated, and in the master branch it's removed. So perhaps this comment is too late to be useful. Is the solution of the problem with the iterators to simply remove them?
(In reply to comment #12) > Is the solution of the problem with the iterators to simply remove them? Sorry yes, they have been removed in gtkmm 3 (2.91.x so far). They can only be brought back if someone adds support for it in the GTK+ C API. They were using direct struct access which is now (wisely) impossible.