diff --git a/include/wx/string.h b/include/wx/string.h index 418dd0d704..fe6394dbe5 100644 --- a/include/wx/string.h +++ b/include/wx/string.h @@ -884,10 +884,18 @@ public: const_iterator operator-(ptrdiff_t n) const { return const_iterator(str(), wxStringOperations::AddToIter(m_cur, -n)); } - // Notice that comparison operators taking non-const iterator are not - // needed here because of the implicit conversion from non-const iterator - // to const ones ensure that the versions for const_iterator declared - // inside WX_STR_ITERATOR_IMPL can be used. + // Until C++20 we could avoid defining these comparison operators because + // the implicit conversion from iterator to const_iterator was used to + // reuse the operators defined inside WX_STR_ITERATOR_IMPL. However in + // C++20 the operator overloads with reversed arguments would be used + // instead, resulting in infinite recursion, so we do need them and, just + // for consistency, define them in all cases. + bool operator==(const iterator& i) const; + bool operator!=(const iterator& i) const; + bool operator<(const iterator& i) const; + bool operator>(const iterator& i) const; + bool operator<=(const iterator& i) const; + bool operator>=(const iterator& i) const; private: // for internal wxString use only: @@ -954,10 +962,13 @@ public: const_iterator operator-(ptrdiff_t n) const { return const_iterator(wxStringOperations::AddToIter(m_cur, -n)); } - // As in UTF-8 case above, we don't need comparison operators taking - // iterator because we have an implicit conversion from iterator to - // const_iterator so the operators declared by WX_STR_ITERATOR_IMPL will - // be used. + // See comment for comparison operators in the UTF-8 case above. + bool operator==(const iterator& i) const; + bool operator!=(const iterator& i) const; + bool operator<(const iterator& i) const; + bool operator>(const iterator& i) const; + bool operator<=(const iterator& i) const; + bool operator>=(const iterator& i) const; private: // for internal wxString use only: @@ -3934,6 +3945,19 @@ inline bool operator!=(const wxString& s, wchar_t c) { return !s.IsSameAs(c); } // wxString iterators comparisons +inline bool wxString::const_iterator::operator==(const iterator& i) const + { return *this == const_iterator(i); } +inline bool wxString::const_iterator::operator!=(const iterator& i) const + { return *this != const_iterator(i); } +inline bool wxString::const_iterator::operator<(const iterator& i) const + { return *this < const_iterator(i); } +inline bool wxString::const_iterator::operator>(const iterator& i) const + { return *this > const_iterator(i); } +inline bool wxString::const_iterator::operator<=(const iterator& i) const + { return *this <= const_iterator(i); } +inline bool wxString::const_iterator::operator>=(const iterator& i) const + { return *this >= const_iterator(i); } + inline bool wxString::iterator::operator==(const const_iterator& i) const { return i == *this; } inline bool wxString::iterator::operator!=(const const_iterator& i) const @@ -4006,9 +4030,7 @@ namespace std WXDLLIMPEXP_BASE wxSTD ostream& operator<<(wxSTD ostream&, const wxString&); WXDLLIMPEXP_BASE wxSTD ostream& operator<<(wxSTD ostream&, const wxCStrData&); WXDLLIMPEXP_BASE wxSTD ostream& operator<<(wxSTD ostream&, const wxScopedCharBuffer&); -#ifndef __BORLANDC__ WXDLLIMPEXP_BASE wxSTD ostream& operator<<(wxSTD ostream&, const wxScopedWCharBuffer&); -#endif #if wxUSE_UNICODE && defined(HAVE_WOSTREAM) diff --git a/src/common/string.cpp b/src/common/string.cpp index d2bcac8b03..7f0a657366 100644 --- a/src/common/string.cpp +++ b/src/common/string.cpp @@ -207,12 +207,14 @@ wxSTD ostream& operator<<(wxSTD ostream& os, const wxScopedCharBuffer& str) return os << str.data(); } -#ifndef __BORLANDC__ wxSTD ostream& operator<<(wxSTD ostream& os, const wxScopedWCharBuffer& str) { - return os << str.data(); + // There is no way to write wide character data to std::ostream directly, + // but we need to define this operator for compatibility, as we provided it + // since basically always, even if it never worked correctly before. So do + // the only reasonable thing and output it as UTF-8. + return os << wxConvWhateverWorks.cWC2MB(str.data()); } -#endif #if wxUSE_UNICODE && defined(HAVE_WOSTREAM) diff --git a/tests/testprec.h b/tests/testprec.h index 38e2ce14e0..4f9068994a 100644 --- a/tests/testprec.h +++ b/tests/testprec.h @@ -55,6 +55,31 @@ #define wxDEFAULT_MANTISSA_SIZE_3 #endif +// Many tests use wide characters or wide strings inside Catch macros, which +// requires converting them to string if the check fails. This falls back to +// std::ostream::operator<<() by default, which never worked correctly, as there +// never was any overload for wchar_t and so it used something else, but in C++ +// 20 this overload is explicitly deleted, so it results in compile-time error. +// +// Hence define this specialization to allow compiling such comparisons. +namespace Catch +{ + +template <> +struct StringMaker +{ + static std::string convert(wchar_t wc) + { + if ( wc < 0x7f ) + return std::string(static_cast(wc), 1); + + return wxString::Format("U+%06X", wc).ToStdString(); + } +}; + +} // namespace Catch + + // thrown when assert fails in debug build class TestAssertFailure {