opAssign and const?

Jonathan M Davis jmdavisProg at gmx.com
Fri May 4 20:31:47 PDT 2012


On Saturday, May 05, 2012 05:15:00 Era Scarecrow wrote:
> On Saturday, 5 May 2012 at 02:21:06 UTC, Jonathan M Davis wrote:
> > As I understand it, you don't need to do _anything_ special to
> > avoid having a temporary copied when passed to your function.
> > Because it's a  temporary, it should be moved into the function
> > parameter, not copied. No  postblit or opAssign will be
> > executed. It's only when it's _not_ a  temporary that a copy
> > will be made. And even in _that_ case, it should be a move if
> > that function call is the last place that the variable is used.
> 
>   That's what I originally thought too... But when I'm dealing
> with the temporary there's something broken. So if I only have
> only the ref.
> 
> Error: function X.opAssign (ref X rhs) is not callable using
> argument types (X)
> 
> so;
> struct X {
>    ref X opAssign(ref X rhs);
> }
> 
>   X func();
> 
> struct Y {
>    X x;
>    this() {
>      x = func();
>    }
> }
> 
>   Unless there's a default it drops back to, it is only seeing the
> one assign function.

If you've declared an opAssign, I'd be very surprised if _any_ assignment 
worked which didn't work with the opAssign that you declared. Once you've 
declared an opAssign, you've taken over the assignment operator, and you need 
to define it for all of the types that you want it to work with.

> > So, I believe that you're trying to avoid copies that will
> > never happen anyway. They would if you were dealing with C++ -
> > particularly  C++98 - but not in D (C++11 fixes the problem via
> > move constructors).
> 
>   I'm not trying to avoid copying (Blocks are small so it's likely
> a tiny cost); I'm trying to keep arrays separate.  Let's add to
> my example; I Hope I got it right based on the behavior I'm
> seeing.
> 
> struct X {
>    ubyte[] buffer;
>    this(ubyte[] b) {
>      buffer = b;
>    }
>    ref X opAssign(ref X rhs);
> }
> 
> X func() {
>    return X(new ubyte[5]);
> }
> 
> void func2(){
>   ubyte[15] buff;
>   X x1 = X(buff[0 .. 5]);
>   X x2 = X(buff[5 .. 10]);
>   const X x3 = X(buff[10 .. $]);
> 
>   x1 = x2; //should use ref, opAssign required to keep addresses
> separate
>   assert(x1.buff !is x2.buff); //must pass, else value semantics
> I'm using breaks
> 
>   x1 = func(); //default copy can work, but fails due to
> opAssign(ref X) existing. Works with opAssign(X)
> 
>   x1 = x3;  //should fail and needs a (const X) or (ref const X).
> 
>   //but if you change to (ref const X),
>   x1 = x2;  //then opAssign(X) runs, making arrays x1 & x2 point
> to the same place; not what i want.
> }
> 
>   In my thinking i make (ref const X) then mutable versions should
> work too; but somehow it's deciding to use (X) instead of (ref
> const X). I'm promising I won't change the data, not requiring
> the data can't be changed.

According to http://dlang.org/function.html:

---------
Func­tions are over­loaded based on how well the ar­gu­ments to a func­tion 
can match up with the pa­ra­me­ters. The func­tion with the best match is se­
lected. The lev­els of match­ing are: 

1. no match
2. match with im­plicit con­ver­sions
3. match with con­ver­sion to const
4. exact match
---------

It picks opAssign(X) over opAssign(ref const X) with an argument of type X, 
because opAssign(X) is an exact match (#4) whereas opAssign(ref const X) 
requires a conversion to const (#3).

- Jonathan M Davis


More information about the Digitalmars-d-learn mailing list