Fix silent wxString comparison breakage in C++20 with std::tuple etc. (PR #26306)

13 views
Skip to first unread message

Václav Slavík

unread,
Mar 17, 2026, 11:53:56 AM (15 hours ago) Mar 17
to wx-...@googlegroups.com, Subscribed

This PR implements C++20’s spaceship operator for wxString.

This is not just nice-to-have, but prevents silent breakage of wxString comparison in user code compiled as C++20 using the recommended configuration of wx, with wxNO_UNSAFE_WXSTRING_CONV defined. Strings end up being compared by their wchar_t* pointer values, not string content. Hence the somewhat inflammatory title of the PR, even though the impact is limited to less commonly needed std containers.

How is this possible? The standard library implements comparison using <=> in C++20 if the operator is available. But wxString doesn’t have it, so it shouldn’t matter for it, right? Surprisingly, that’s not the case:

// this assert, surprisingly, doesn’t fail
static_assert(std::three_way_comparable<wxString>);

Turns out, the spaceship operator is available through implicit conversion to wchar_t pointers:

Consequently, std::tie, std::tuple, std::vector (and who knows what else) comparison uses it for wxString content.

The behavior depends on the macros defined:

  1. wxNO_UNSAFE_WXSTRING_CONV defined, as recommended by wx docs → fails silently
  2. wxNO_IMPLICIT_WXSTRING_CONV_TO_PTR prevents the problem for self-evident reasons
  3. Neither defined → OK by a lucky break: there's two implicit conversions to pointers and the compiler can’t decide, ergo not three-way-comparable

This also makes it challenging to write a test for the suite — it doesn’t show with wx’s build-time settings, so merely putting the test in there would be a noop. I was using this for testing (and understanding the effect of the macros):

#define wxNO_UNSAFE_WXSTRING_CONV 1
#include <wx/string.h>

TEST_CASE("StringTupleCompare", "[wxString]")
{
    wxString a(wxT("bar"));
    wxString b(wxT("bar"));

    REQUIRE(a == b);
    REQUIRE(static_cast<const wchar_t*>(a) != static_cast<const wchar_t*>(b));

    CHECK_FALSE(std::tie(a) < std::tie(b));
    CHECK_FALSE(std::tie(b) < std::tie(a));
}

IMNSHO this fix needs to be backported to 3.2 too.


You can view, comment on, or merge this pull request online at:

  https://github.com/wxWidgets/wxWidgets/pull/26306

Commit Summary

  • 41a1390 Implement C++20 three-way comparison for wxString

File Changes

(1 file)

Patch Links:


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/pull/26306@github.com>

Václav Slavík

unread,
Mar 17, 2026, 12:13:17 PM (14 hours ago) Mar 17
to wx-...@googlegroups.com, Push

@vslavik pushed 1 commit.

  • 6f93534 Implement C++20 three-way comparison for wxString


View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/pull/26306/before/41a13908f73c2432b0cd4717da7bee1797d83683/after/6f935341b235f78de25053b3d5fd6ca409833736@github.com>

Václav Slavík

unread,
Mar 17, 2026, 12:14:02 PM (14 hours ago) Mar 17
to wx-...@googlegroups.com, Subscribed
vslavik left a comment (wxWidgets/wxWidgets#26306)

(...and force-pushed simplified version that has the advantage of actually working with MSVC)


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/pull/26306/c4076190782@github.com>

VZ

unread,
Mar 17, 2026, 2:08:58 PM (12 hours ago) Mar 17
to wx-...@googlegroups.com, Subscribed
vadz left a comment (wxWidgets/wxWidgets#26306)

Thanks for fixing this!

Could we perhaps at least add a C++20 build to test that <=> works correctly for wxString? This is what counts, after all...

We can backport it to 3.2 if no problems are found, but I'd like to do at least some testing in master first, so I won't do it immediately.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/pull/26306/c4076987679@github.com>

Reply all
Reply to author
Forward
0 new messages