Don't clobber std::string_view equality with char *

Make the wxString(std::string_view) constructor explicit.

Otherwise, when comparing a std::string_view with a const char *, the
cast to wxString will be considered as a candidate for the comparison,
ultimately causing an "ambiguous overload for 'operator=='" error.

For example, this sample only builds if the constructor is explicit:

  #include <wx/string.h>
  #include <string_view>

  int main() {
    std::string_view view = "abc";
    const char *str = "abc";
    return view == str;
  }

However, making the constructor explicit will break assignment:

    std::string_view view = "abc";
    wxString s;
    s = view; // Error: no match for "operator="

That we can fix by implementing operator=(std::string_view)

That, however, introduces another ambiguity:

    std::string str = "abc";
    wxString s;
    s = str; // Ambiguous between s = wxString(str)
                              and s = std::string_view(str)

That we can fix by implementing operator=(std::string)

Finally, note that some rather obscure ambiguities remain, such as:

    wxString s;
    s = {"abc", 2}; // Ambiguous between s = wxString("abc", 2)
                                     and s = std::string_view("abc", 2)

Avoiding them is not simple (https://cplusplus.github.io/LWG/issue2946)
and doesn't add much value.

Closes #23834.
This commit is contained in:
Joan Bruguera Micó 2023-08-28 23:53:14 +00:00 committed by Vadim Zeitlin
parent b3cfab1433
commit 19936c2176
3 changed files with 39 additions and 2 deletions

View file

@ -108,6 +108,11 @@ Changes in behaviour which may result in build errors
compatible with the previous wxWidgets versions, but now compare values, and compatible with the previous wxWidgets versions, but now compare values, and
not pointers, in their Index() member function. not pointers, in their Index() member function.
- Due to the possibility to construct wxString from std::string_view some
previously valid code, such as "wxstr = {"Hello", 2}", is now ambiguous.
Please use explicit class name, e.g. "wxstr = wxString{"Hello", 2}" to
preserve the previous behaviour.
- Generic wxSearchCtrl doesn't provide methods that make sense only for - Generic wxSearchCtrl doesn't provide methods that make sense only for
multiline text controls any longer, for consistency with the other ports. multiline text controls any longer, for consistency with the other ports.

View file

@ -1263,7 +1263,7 @@ public:
#endif #endif
#ifdef wxHAS_STD_STRING_VIEW #ifdef wxHAS_STD_STRING_VIEW
wxString(std::wstring_view view) explicit wxString(std::wstring_view view)
{ assign(view.data(), view.length()); } { assign(view.data(), view.length()); }
#endif // wxHAS_STD_STRING_VIEW #endif // wxHAS_STD_STRING_VIEW
@ -1272,7 +1272,7 @@ public:
{ assign(str.c_str(), str.length()); } { assign(str.c_str(), str.length()); }
#ifdef wxHAS_STD_STRING_VIEW #ifdef wxHAS_STD_STRING_VIEW
wxString(std::string_view view) explicit wxString(std::string_view view)
{ assign(view.data(), view.length()); } { assign(view.data(), view.length()); }
#endif // wxHAS_STD_STRING_VIEW #endif // wxHAS_STD_STRING_VIEW
#endif // wxNO_IMPLICIT_WXSTRING_ENCODING #endif // wxNO_IMPLICIT_WXSTRING_ENCODING
@ -1883,6 +1883,29 @@ public:
{ return assign(s); } { return assign(s); }
#endif // wxNO_IMPLICIT_WXSTRING_ENCODING #endif // wxNO_IMPLICIT_WXSTRING_ENCODING
#if wxUSE_UNICODE_WCHAR
wxString& operator=(const std::wstring& str) { m_impl = str; return *this; }
wxString& operator=(std::wstring&& str) noexcept { m_impl = std::move(str); return *this; }
#else // wxUSE_UNICODE_UTF8
wxString& operator=(const std::wstring& str)
{ return assign(str.c_str(), str.length()); }
#endif
#ifdef wxHAS_STD_STRING_VIEW
wxString& operator=(std::wstring_view view)
{ return assign(view.data(), view.length()); }
#endif // wxHAS_STD_STRING_VIEW
#ifndef wxNO_IMPLICIT_WXSTRING_ENCODING
wxString& operator=(const std::string& str)
{ return assign(str.c_str(), str.length()); }
#ifdef wxHAS_STD_STRING_VIEW
wxString& operator=(std::string_view view)
{ return assign(view.data(), view.length()); }
#endif // wxHAS_STD_STRING_VIEW
#endif // wxNO_IMPLICIT_WXSTRING_ENCODING
// string concatenation // string concatenation
// in place concatenation // in place concatenation
/* /*

View file

@ -690,5 +690,14 @@ TEST_CASE("StdString::View", "[stdstring]")
std::string_view strViewInvalidUTF(strInvalidUTF); std::string_view strViewInvalidUTF(strInvalidUTF);
CHECK( "" == wxString::FromUTF8(strViewInvalidUTF) ); CHECK( "" == wxString::FromUTF8(strViewInvalidUTF) );
/* Ensure we don't clobber comparisons on base types */
std::string_view view = "abc";
const char *str = "abc";
CHECK( view == str );
std::wstring_view wview = L"abc";
const wchar_t *wstr = L"abc";
CHECK( wview == wstr );
} }
#endif // wxHAS_STD_STRING_VIEW #endif // wxHAS_STD_STRING_VIEW