How to make a proxy class use a specific conversion for a specific use case

Viewed 38

I have a very complex string class whose implementation uses copy-on-write, so it has a special proxy class arec_t to determine whether access to a member is a write or a read, defined roughly like this

class arec_t: non_copyable,non_moveable{
    string_t* _to;
    size_t    _index;

    friend class string_t;
public:
    arec_t(string_t* to,size_t index)noexcept:_to(to),_index(index){}
    arec_t(special_init_t,const arec_t&ref)noexcept:_to(ref._to),_index(ref._index){}
    [[nodiscard]]operator char_T()&&noexcept{ return _to->arec(_index); }
    [[nodiscard]]operator char_T()const&&noexcept{ return _to->arec(_index); }
    arec_t&&     operator=(char_T a)&&noexcept{
        _to->arec_set(_index,a);
        return move(*this);
    }
    arec_t&&     operator=(const arec_t&&ch)&&noexcept{ return move(*this).operator=(move(ch).operator char_T()); }
private:
    [[nodiscard]]char_T*        get_address()noexcept{ return _to->unique_c_str()+_index; }
    [[nodiscard]]const char_T*  get_address()const noexcept{ return (add_const(_to))->c_str()+_index; }
public:
    [[nodiscard]]char_T*        operator&()&&noexcept{ return get_address(); }
    [[nodiscard]]const char_T*  operator&()const&&noexcept{ return get_address(); }
    [[nodiscard]]explicit operator char_T&()&&noexcept{ return *get_address(); }
};

[[nodiscard]]arec_t       operator[](size_t index)noexcept{ return{this,index}; }
[[nodiscard]]const arec_t operator[](size_t index)const noexcept{ return{remove_const(this),index}; }

Most of its available member methods are right-valued only, which is intended to avoid problems with declarations like auto c=str[0]; then use c as a char_T

I then have to describe how the different methods affect the string class in order to explain the problem I'm having: for a single member access, string_t::arec is the fastest and doesn't trigger any memory copies, while the string_t::c_str function will cause possible memory copies at a much slower rate, and the string_t::unique_c_str is the one with the most overhead

With the preliminaries out of the way, here are the points of confusion.

In my tests today, a "range for" in the shape of for(char_t&c : str) is disabled because the function arec_t to char_T& is declared as explicit. My attempt to remove explicit from arec_t::operator char_T& triggered other problems: the compiler reported an error for such a function because there are multiple overloading routes

char_t my_func(string_t<char_t>str){return str[rand()];}

And it seems that the compiler overloads char_t c=str[0] onto arec_t::operator char_T& instead of arec_t::operator char_T, where the former indirectly calls string_t::unique_c_str and the latter calls string_t::arec

I don't know how to modify the proxy class arec_t to do all that I want, including these:

  1. allow the "range for" of string_t as chat_T&
  2. call arec_t::operator char_T instead of arec_t::operator char_T& when converting arec_t to char_T but only using the value to avoid unnecessary performance loss
  3. in most cases (includes assignment, passing as a parameter, comparison) arec_t behaves like a char_T without the need for additional writing for conversion
0 Answers
Related