Hide operator<<() overloads for wxString and related classes

As not defining operator<<() overload taking wxScopedCharBuffer in the
global scope prevents it from being considered as an overload resolution
candidate (which is, of course, the whole point), it also prevents it
from being used for the classes convertible to it, such as wxCharBuffer,
so we need to define operator<<() overloaded for the latter explicitly
too.

We also need a new wxScopedCharTypeBufferStreamSupport helper in order
to define different operators inside different specializations of
wxScopedCharTypeBuffer<>.
This commit is contained in:
Vadim Zeitlin 2024-01-06 23:04:27 +01:00
parent 3b62433a3f
commit 2349586e28
3 changed files with 112 additions and 24 deletions

View file

@ -13,6 +13,10 @@
#include "wx/defs.h"
#include "wx/wxcrtbase.h"
#if wxUSE_STD_IOSTREAM
#include "wx/iosfwrap.h"
#endif
#include <stdlib.h> // malloc() and free()
class WXDLLIMPEXP_FWD_BASE wxCStrData;
@ -55,14 +59,70 @@ struct UntypedBufferData
// NB: this is defined in string.cpp and not the (non-existent) buffer.cpp
WXDLLIMPEXP_BASE UntypedBufferData * GetUntypedNullData();
// Implementation of stream insertion operators: they can't be inline because
// we don't have full std::ostream declaration here.
#if wxUSE_STD_IOSTREAM
WXDLLIMPEXP_BASE std::ostream& OutputCharBuffer(std::ostream&, const char* s);
WXDLLIMPEXP_BASE std::ostream& OutputWCharBuffer(std::ostream&, const wchar_t* ws);
#if defined(HAVE_WOSTREAM)
WXDLLIMPEXP_BASE std::wostream& OutputWCharBuffer(std::wostream&, const wchar_t* ws);
#endif // defined(HAVE_WOSTREAM)
#endif // wxUSE_STD_IOSTREAM
} // namespace wxPrivate
// Template used as CRTP base class for wxScopedCharTypeBuffer in order to
// define overloaded operator<<() for it.
//
// By default we don't define any operators, but we do define them for the
// usual char and wchar_t specializations below.
template <typename T, typename Buffer>
struct wxScopedCharTypeBufferStreamSupport
{
};
// Suppress the warning about declaring a non-template friend because this is
// exactly what we want to do here.
wxGCC_ONLY_WARNING_SUPPRESS(non-template-friend)
template <typename Buffer>
struct wxScopedCharTypeBufferStreamSupport<char, Buffer>
{
#if wxUSE_STD_IOSTREAM
friend std::ostream& operator<<(std::ostream& oss, const Buffer& buf)
{
return wxPrivate::OutputCharBuffer(oss, buf.data());
}
#endif // wxUSE_STD_IOSTREAM
};
template <typename Buffer>
struct wxScopedCharTypeBufferStreamSupport<wchar_t, Buffer>
{
#if wxUSE_STD_IOSTREAM
friend std::ostream& operator<<(std::ostream& oss, const Buffer& buf)
{
return wxPrivate::OutputWCharBuffer(oss, buf.data());
}
#if defined(HAVE_WOSTREAM)
friend std::wostream& operator<<(std::wostream& woss, const Buffer& buf)
{
return wxPrivate::OutputWCharBuffer(woss, buf.data());
}
#endif // defined(HAVE_WOSTREAM)
#endif // wxUSE_STD_IOSTREAM
};
wxGCC_ONLY_WARNING_RESTORE(non-template-friend)
// Reference-counted character buffer for storing string data. The buffer
// is only valid for as long as the "parent" object that provided the data
// is valid; see wxCharTypeBuffer<T> for persistent variant.
template <typename T>
class wxScopedCharTypeBuffer
: wxScopedCharTypeBufferStreamSupport<T, wxScopedCharTypeBuffer<T>>
{
public:
typedef T CharType;
@ -368,6 +428,13 @@ public:
wxCharBuffer(size_t len) : wxCharTypeBufferBase(len) {}
wxCharBuffer(const wxCStrData& cstr);
#if wxUSE_STD_IOSTREAM
// Define this to disambiguate between converting to the base class or to
// wxString when using operator<<() with the objects of this class.
friend WXDLLIMPEXP_BASE
std::ostream& operator<<(std::ostream& oss, const wxCharBuffer& buf);
#endif // wxUSE_STD_IOSTREAM
};
class wxWCharBuffer : public wxCharTypeBuffer<wchar_t>
@ -385,6 +452,16 @@ public:
wxWCharBuffer(size_t len) : wxCharTypeBufferBase(len) {}
wxWCharBuffer(const wxCStrData& cstr);
#if wxUSE_STD_IOSTREAM
// See wxCharBuffer for why this is needed.
friend WXDLLIMPEXP_BASE
std::ostream& operator<<(std::ostream& oss, const wxWCharBuffer& buf);
#if defined(HAVE_WOSTREAM)
friend WXDLLIMPEXP_BASE
std::wostream& operator<<(std::wostream& woss, const wxWCharBuffer& buf);
#endif // defined(HAVE_WOSTREAM)
#endif // wxUSE_STD_IOSTREAM
};
// wxCharTypeBuffer<T> implicitly convertible to T*, for char and wchar_t,