const ref in opAssign

Jonathan M Davis jmdavisProg at gmx.com
Tue Jun 26 08:40:04 PDT 2012


On Tuesday, June 26, 2012 14:44:45 monarch_dodra wrote:
> I just finished reading the chapters on user defined types and,
> (as a C++ dev), this one line struc out to me as very odd:
> 
> "ref Widget opAssign(ref Widget rhs) {..}"
> 
> This means that during an assignment, I could potentially change
> "Other" (!). This seems like a blatant violation of the expected
> behavior of =. What's more, it prevents the assignment from a
> const object...
> 
> I am very tempted to change the call to "const ref". Is this
> un-advised?
> 
> Mr. Alexandrescu goes on to mention a "pass by value" in case you
> wanted to assign from a temporary, mentioning:
> w = Widget(50); // Error!
> // Cannot bind an rvalue of type Widget to ref Widget!
> 
> The only problem is that if I do this, all of my calls are then
> re-routed to pass by value, and none to the pass-by-const-ref.
> 
> ----
> 
> Is there any way to enforce const correctness, while still
> keeping advantage of both calls?
> 
> PS: using Mr. Alexandrescu's design, it is not possible to assign
> from a const Widget, I get:
> hello.d(50): Error: function hello.Widget.opAssign (Widget rhs)
> is not callable using argument types (const(Widget))
> hello.d(50): Error: cannot implicitly convert expression (w2) of
> type const(Widget) to Widget
> 
> const can't be passed by value...?

Depending on your type, taking const ref Widget would be a big problem, 
because you wouldn't be able to assign a const member variable's value of rhs 
to a non-const member variable of this (e.g. if it's a class) without making a 
deep copy. Or it could be just fine. It all depends on your type and what 
you're trying to do. Regardless, the solution is almost certainly to have 
multiple overloads. Each of the overloads does this

// Works with any Widget if Widget is a value type and any non-const Widget
// if it's a reference type.
ref Widget opAssign(Widget rhs) {}

// Works with any Widget as long as you can copy all of the member variables
// when they're const.
ref Widget opAssign(const Widget rhs) {}

// Works with non-const Widgets which are lvalues only.
ref Widget opAssign(ref Widget rhs) {}

// Works with any Widgets which are lvalues as long as you can copy all of the
// member variables when they're const.
ref Widget opAssign(ref Widget rhs) {}

In most cases, I would expect you to have these two overloads

ref Widget opAssign(const Widget rhs) {}
ref Widget opAssign(const ref Widget rhs) {}

It then works with const (as long as you're not dealing with a type which 
can't really be copied when it's const) and both rvalues and lvalues. The 
rvalue version must be const to ensure that constness does not affect which 
overload gets called (just l/rvalue-ness). This is particularly critical if 
the rvalue version simply calls the lvalue version, because if it's not const, 
you'd get infinite recursion.

- Jonathan M Davis


More information about the Digitalmars-d mailing list