Thread overview
Passing rvalues to functions expecting const ref
Dec 23, 2012
Minas Mina
Dec 23, 2012
Namespace
Dec 23, 2012
Minas Mina
Dec 23, 2012
John Chapman
Dec 23, 2012
Namespace
Dec 23, 2012
Minas Mina
Dec 23, 2012
Minas Mina
December 23, 2012
Hi. In C++, I can do this:

struct Vector3
{
  Vector3(_x, _y, _z); // constructor
};

float dot(const Vector3 &v, const Vector3 &u);

dot(Vector3(0, 0, 0), Vector3(1, 1, 1));
------------------------------------

In D, I can't -- and it's really annoying, because I am forced to make a copy, i.e:
dot(Vector3 v, Vector3 u);

I don't want this.

The other solution is this:
Vector3 v = {0, 0, 0};
Vector3 u = {1, 1, 1};

dot(v,u); // dot(const ref Vector3 v, const ref Vector3 u);

But it's not as clean.
Why can't I do what I can in C++? Is it a technical or a design decision? Are there plans to support it?
December 23, 2012
As long as you use structs this should work, as you can see here: http://dpaste.dzfl.pl/03adf3d1
But if you use classes, it does not work anymore. So I like it a lot, that it works with structs. :)
December 23, 2012
On Sunday, 23 December 2012 at 12:08:47 UTC, Namespace wrote:
> As long as you use structs this should work, as you can see here: http://dpaste.dzfl.pl/03adf3d1
> But if you use classes, it does not work anymore. So I like it a lot, that it works with structs. :)

Thank you. I had forgotten to supply the constructor to the struct :/
December 23, 2012
On Sunday, 23 December 2012 at 12:08:47 UTC, Namespace wrote:
> As long as you use structs this should work, as you can see here: http://dpaste.dzfl.pl/03adf3d1
> But if you use classes, it does not work anymore. So I like it a lot, that it works with structs. :)

I don't think this will work after 2.061 is released. The behaviour is changing to disallow struct literals as lvalues.
December 23, 2012
There's another problem though:

struct Vector3
{
	float x, y, z;
	
	this(float _x, float _y, float _z)
	{
		x = _x;
		y = _y;
		z = _z;
	}
	
	// the binary +, - operators are defined
}

Vector3 cross(const ref Vector3 a, const ref Vector3 b);
...

Vector3 n = cross(b-a, c-a);


raytracing/triangle.d(58): Error: function raytracing.vector.cross (ref const(Vector3) a, ref const(Vector3) b) is not callable using argument types (Vector3,Vector3)
raytracing/triangle.d(58): Error: this.b.opBinary(this.a) is not an lvalue
raytracing/triangle.d(58): Error: this.c.opBinary(this.a) is not an lvalue

That's what I actually want.
December 23, 2012
On Sunday, 23 December 2012 at 18:32:47 UTC, John Chapman wrote:
> On Sunday, 23 December 2012 at 12:08:47 UTC, Namespace wrote:
>> As long as you use structs this should work, as you can see here: http://dpaste.dzfl.pl/03adf3d1
>> But if you use classes, it does not work anymore. So I like it a lot, that it works with structs. :)
>
> I don't think this will work after 2.061 is released. The behaviour is changing to disallow struct literals as lvalues.

I hope not. As long as "auto ref" don't work for normal functions, this change would be very inconvenient...

Minas Mina:
Show me the whole code, I think that your opBinary functions returns rvalues.
This would be a good and important case for "auto ref". But until now it is only for template paramters...
December 23, 2012
On Sunday, 23 December 2012 at 20:40:09 UTC, Namespace wrote:
> Minas Mina:
> Show me the whole code, I think that your opBinary functions returns rvalues.
> This would be a good and important case for "auto ref". But until now it is only for template paramters...

struct Vector3
{
	float x, y, z;
	
	this(float _x, float _y, float _z)
	{
		x = _x;
		y = _y;
		z = _z;
	}
	
	// negate operator
	Vector3 opUnary(string s)() const if( s == "-" )
	{
		Vector3 temp = this;
		
		temp.x = -temp.x;
		temp.y = -temp.y;
		temp.z = -temp.z;
		
		return temp;
	}
	
	// + operator for completeness
	Vector3 opUnary(string s)() const if( s == "+" )
	{
		return this;
	}
	
	// binary operators
	Vector3 opBinary(string op) (float val) const
	{
		static if( op == "+" )
		{
			Vector3 temp = this;
			temp.x += val;
			temp.y += val;
			temp.z += val;
		}
		else static if( op == "-" )
		{
			Vector3 temp = this;
			temp.x -= val;
			temp.y -= val;
			temp.z -= val;
		}
		else static if( op == "*" )
		{
			Vector3 temp = this;
			temp.x *= val;
			temp.y *= val;
			temp.z *= val;
		}
		else static if( op == "/" )
		{
			Vector3 temp = this;
			temp.x /= val;
			temp.y /= val;
			temp.z /= val;
		}
		
		return temp;
	}
	
	Vector3 opBinary(string op) (Vector3 v) const
	{
		static if( op == "+" )
		{
			Vector3 temp = this;
			temp.x += v.x;
			temp.y += v.y;
			temp.z += v.z;
		}
		static if( op == "-" )
		{
			Vector3 temp = this;
			temp.x -= v.x;
			temp.y -= v.y;
			temp.z -= v.z;
		}
		static if( op == "*" )
		{
			Vector3 temp = this;
			temp.x *= v.x;
			temp.y *= v.y;
			temp.z *= v.z;
		}
		
		return temp;
	}
}

/// dot product of two Vector3 vectors
@safe pure float dot(Vector3 u, Vector3 v)
{
	return u.x * v.x + u.y * v.y + u.z * v.z;
}

dot is making copies now because what I have shown earlier does not work... It's what I'm using now.