<div dir="ltr"><div>Hi,</div><div><br></div><div>&gt; 
So we start out with a structure that can pretend it&#39;s an &#39;std::string&#39;:</div><div><br></div><div>Or just don&#39;t. Don&#39;t bandaid over a bad library, fix the library or just give up on using string_view in your code. This is GUI too, copying a string probably isn&#39;t performance critical for you.</div><div><br></div><div>Jeremy</div></div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Mon, Jun 16, 2025 at 6:02 PM Frederick Virchanza Gotham via Std-Proposals &lt;<a href="mailto:std-proposals@lists.isocpp.org">std-proposals@lists.isocpp.org</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">I&#39;m writing a program at the moment using the wxWidgets library for<br>
showing windows on screen. Some of the constant strings in the program<br>
are very long, and they get copied in a few places because some of the<br>
wxWidgets library functions take a &quot;wxString const &amp;&quot; as an argument.<br>
wxString is similar to std::string in that it provides storage for the<br>
string and allocates memory dynamically if necessary, and so all my<br>
constexpr strings gets copied when I create the wxString object.<br>
<br>
For the purposes of this email I&#39;m going to switch over to the C++<br>
standard library, and so I&#39;ll talk about the std::string class. Let&#39;s<br>
say there&#39;s a function in a 3rd party library as follows:<br>
<br>
    size_t CountWords(string const &amp;s)<br>
    {<br>
        std::size_t count = 1u;<br>
        for ( char const c : s )<br>
        {<br>
            if ( c == &#39; &#39; ) ++count;<br>
        }<br>
        return count;<br>
    }<br>
<br>
Now we could argue that this function should really take a &#39;char*&#39; or<br>
a &#39;string_view&#39;, but let&#39;s assume that we can&#39;t change a pre-compiled<br>
proprietary library. It takes a &#39;string&#39; and we just have to deal with<br>
it.<br>
<br>
Now let&#39;s say we have a semi-long constexpr string as follows:<br>
<br>
    constexpr char g_poem[] =<br>
        &quot;Had I the heavens’ embroidered cloths,\n&quot;<br>
        &quot;Enwrought with golden and silver light,\n&quot;<br>
        &quot;The blue and the dim and the dark cloths\n&quot;<br>
        &quot;Of night and light and the half-light,\n&quot;<br>
        &quot;I would spread the cloths under your feet:\n&quot;<br>
        &quot;But I, being poor, have only my dreams;\n&quot;<br>
        &quot;I have spread my dreams under your feet;\n&quot;<br>
        &quot;Tread softly because you tread on my dreams.&quot;;<br>
<br>
This string is not nearly as long as some of the strings I have<br>
hardcoded into my current program (e.g. the full hex values of a PDF<br>
file for a C++ proposal paper). But let&#39;s say that we really don&#39;t<br>
want to copy this string. Some how, some way, though, we need to pass<br>
this as a &#39;std::string const &amp;&#39; without copying the string.<br>
<br>
So we start out with a structure that can pretend it&#39;s an &#39;std::string&#39;:<br>
<br>
    template&lt;typename T&gt; requires std::is_same_v&lt; T, std::remove_cvref_t&lt;T&gt; &gt;<br>
    struct Pretender {<br>
        union {<br>
            alignas(T) char unsigned  m8[sizeof(T)];<br>
            alignas(T) std::uint16_t m16[sizeof(T) / sizeof(std::uint16_t)];<br>
            alignas(T) std::uint32_t m32[sizeof(T) / sizeof(std::uint32_t)];<br>
            alignas(T) std::uint64_t m64[sizeof(T) / sizeof(std::uint64_t)];<br>
            alignas(T)    void const *mp[sizeof(T) / sizeof(    void*    )];<br>
        };<br>
<br>
        Pretender(void) : m8() {}  // start off all bits zero<br>
<br>
        operator T const&amp;(void) const noexcept<br>
        {<br>
            return *static_cast&lt;T const*&gt;(static_cast&lt;void const*&gt;(this));<br>
        }<br>
    };<br>
<br>
And from there we can write a function as follows to pretend that a<br>
span is a container:<br>
<br>
    template&lt;typename T&gt; requires std::is_same_v&lt; T, std::remove_cvref_t&lt;T&gt; &gt;<br>
    Pretender&lt;T&gt; Pretend(typename T::value_type const *const p,<br>
std::size_t const len);<br>
<br>
So then in the implementation of this function, we put specialist code<br>
for &#39;std::string&#39; as follows for libstdc++:<br>
<br>
    template&lt;typename T&gt; requires std::is_same_v&lt; T, std::remove_cvref_t&lt;T&gt; &gt;<br>
    Pretender&lt;T&gt; Pretend(typename T::value_type const *const p,<br>
std::size_t const len)<br>
    {<br>
        Pretender&lt;T&gt; retval;<br>
        if constexpr ( std::is_same_v&lt;T, std::string&gt; )<br>
        {<br>
            static_assert( sizeof(std::string) == 32u );<br>
            <a href="http://retval.mp" rel="noreferrer" target="_blank">retval.mp</a> [0] = p;<br>
            retval.m64[1] = len;<br>
            retval.m64[2] = len;<br>
        }<br>
        return retval;<br>
    }<br>
<br>
So now let&#39;s try it in a GodBolt to see if it works:<br>
<br>
    <a href="https://godbolt.org/z/djWf3q3Gc" rel="noreferrer" target="_blank">https://godbolt.org/z/djWf3q3Gc</a><br>
<br>
This strategy also works for other contiguous containers. Let&#39;s say we<br>
have a 3rd party library with an exported function such as:<br>
<br>
    void Func( std::vector&lt;double&gt; const &amp; );<br>
<br>
But all we have is a std::span&lt;double&gt;. Well we can pretend that the<br>
span is a vector:<br>
<br>
    <a href="https://godbolt.org/z/59WfGz3f4" rel="noreferrer" target="_blank">https://godbolt.org/z/59WfGz3f4</a><br>
<br>
The key here is that the make-believe container must be &#39;const&#39; --<br>
meaning that you can&#39;t edit its elements, can&#39;t resize it, and very<br>
importantly, you can&#39;t move from it.<br>
<br>
Is there any possibility we could have something like this in the<br>
Standard? It can be implemented without an ABI break. I can implement<br>
it in a day or two for all the major C++ standard libraries. . .<br>
Dinkumware, Microsoft, libstdc++, libc++. It&#39;s not much work.<br>
<br>
In my own program I&#39;ll be using this strategy to pretend that a<br>
constexpr char array is a wxString object.<br>
<br>
And for those who want to scream at me to say that my implementations<br>
are undefined behaviour, well try to imagine that I compiled it to<br>
assembler, and then I put inline assembler in a C++ file. No more<br>
undefined behaviour. This can be implemented without an ABI break.<br>
-- <br>
Std-Proposals mailing list<br>
<a href="mailto:Std-Proposals@lists.isocpp.org" target="_blank">Std-Proposals@lists.isocpp.org</a><br>
<a href="https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals" rel="noreferrer" target="_blank">https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals</a><br>
</blockquote></div>

