www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Passing a generic struct as parameter

reply Zardoz <luis.panadero gmail.com> writes:
I have a parametrized struct (Vector!(T, dim)) that takes two parameters 
(Type and a number). And made some Alias with defaults parameters.

In other struct (Matrix!(T, dim)), that uses these struct to represent a 
matrix in column-major order. I have a internall alias for Vector using 
internally (alias Vector!(T,dim_) VCol;) . The problem that I have it's 
when I try to use opIndexAssign to assign to a column a Vector. I try 
this :

void opIndexAssign(Vector v, size_t j) {
	if ( code that see if VCol if same type that v ) {
		col[j] = v;
	} else {
		col[j] = cast (VCol) v;
	}
}

But not compile... I get this error :
Error: struct zmath.vector.Vector(T,ulong dim_) if (__traits
(isFloating,T)) is used as a type
Error: template instance zmath.matrix.Matrix!(float,2) error instantiating

So finally I try this :
/**
* Assigns a new column vector
*/
void opIndexAssign(VCol v, size_t j) {
	col[j] = v;
}

But now I must do cast outside, even knowing that are same type. Plus now 
I must keep VCol alias public.

How should fix this, or What is the correct way of doing this ?


Note : I have a opCast for Vector that cast between Vectors with 
different parameters and it's checked that works.

Second Question : I'm thinking publish this small Vector/Quaternion/
Matrix lib that I made learning D2.. where I should put and how ? (and I 
use Git)

-- 
Yep, I'm afraid that I have a blog : zardoz.es
Jun 30 2011
next sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On 2011-06-30 16:39, Zardoz wrote:
 I have a parametrized struct (Vector!(T, dim)) that takes two parameters
 (Type and a number). And made some Alias with defaults parameters.
 
 In other struct (Matrix!(T, dim)), that uses these struct to represent a
 matrix in column-major order. I have a internall alias for Vector using
 internally (alias Vector!(T,dim_) VCol;) . The problem that I have it's
 when I try to use opIndexAssign to assign to a column a Vector. I try
 this :
 
 void opIndexAssign(Vector v, size_t j) {
 if ( code that see if VCol if same type that v ) {
 col[j] = v;
 } else {
 col[j] = cast (VCol) v;
 }
 }
 
 But not compile... I get this error :
 Error: struct zmath.vector.Vector(T,ulong dim_) if (__traits
 (isFloating,T)) is used as a type
 Error: template instance zmath.matrix.Matrix!(float,2) error instantiating
 
 So finally I try this :
 /**
 * Assigns a new column vector
 */
 void opIndexAssign(VCol v, size_t j) {
 col[j] = v;
 }
 
 But now I must do cast outside, even knowing that are same type. Plus now
 I must keep VCol alias public.
 
 How should fix this, or What is the correct way of doing this ?
 
 
 Note : I have a opCast for Vector that cast between Vectors with
 different parameters and it's checked that works.
 
 Second Question : I'm thinking publish this small Vector/Quaternion/
 Matrix lib that I made learning D2.. where I should put and how ? (and I
 use Git)
The first thing that you need to understand is that Vector is not a type. It does not exist. Vector!(int, 4) is a type. Vector!(float, 3) is a type. Vector is not. Vector is a template for a type. When you use a template, you instantiate it for a particular set of arguments, and that creates a new type. An instantiation of a templated type such as Vector is a type, and every instantiation is its own, separate type which has no connection with any other instantion of that template. So, it makes no sense for a function to take a Vector (though within the Vector template that works, because Vector stands for that particular instantiation inside of the Vector template). If you want a function to take multiple instantiations of a template, then you need to templatize the function. If you want it to take a particular instantiation of a template, then you give its parameter that exact template instantiation. Now, if you want two separate instantions (such as Vector!(int, 3) and Vector! (float, 3)) to interact, you're going to need to either write opCasts to cast between them or have templated functions which are templated on both of their types (e.g. func(V1, V2)(V1 vector1, V2 vector2) {...}). They are two completed different types, just like if you created IntVector and FloatVector, so you have to write code which allows them to interact. They aren't going to just work together because they came from the same template. - Jonathan M Davis
Jun 30 2011
parent Zardoz <luis.panadero gmail.com> writes:
Thanks. I imagined something similar, that "Vector" alone not is type.
How I can templatize opIndexAssign function ? I tried this :

void opIndexAssign(U)(U v, size_t j) {
  col[j] = v;
}

And I get a error : 
Error: template zmath.matrix.Matrix!(float,2).Matrix.opIndexAssign(U) conflicts
with function 
zmath.matrix.Matrix!(float,2).Matrix.opIndexAssign at src/matrix.d(261)

That I interpret that this opIndexAssign clash with other opIndexAssign that I
have to direct access to 
matrix  cells
void opIndexAssign(T c, size_t row, size_t cl) {
	col[cl][row] = c;
}

I said before that I made a opCast for Vector ?

On Fri, 01 Jul 2011 00:12:43 +0000, Jonathan M Davis wrote:

 On 2011-06-30 16:39, Zardoz wrote:
 I have a parametrized struct (Vector!(T, dim)) that takes two
 parameters (Type and a number). And made some Alias with defaults
 parameters.
 
 In other struct (Matrix!(T, dim)), that uses these struct to represent
 a matrix in column-major order. I have a internall alias for Vector
 using internally (alias Vector!(T,dim_) VCol;) . The problem that I
 have it's when I try to use opIndexAssign to assign to a column a
 Vector. I try this :
 
 void opIndexAssign(Vector v, size_t j) { if ( code that see if VCol if
 same type that v ) { col[j] = v;
 } else {
 col[j] = cast (VCol) v;
 }
 }
 
 But not compile... I get this error : Error: struct
 zmath.vector.Vector(T,ulong dim_) if (__traits (isFloating,T)) is used
 as a type
 Error: template instance zmath.matrix.Matrix!(float,2) error
 instantiating
 
 So finally I try this :
 /**
 * Assigns a new column vector
 */
 void opIndexAssign(VCol v, size_t j) { col[j] = v;
 }
 
 But now I must do cast outside, even knowing that are same type. Plus
 now I must keep VCol alias public.
 
 How should fix this, or What is the correct way of doing this ?
 
 
 Note : I have a opCast for Vector that cast between Vectors with
 different parameters and it's checked that works.
 
 Second Question : I'm thinking publish this small Vector/Quaternion/
 Matrix lib that I made learning D2.. where I should put and how ? (and
 I use Git)
The first thing that you need to understand is that Vector is not a type. It does not exist. Vector!(int, 4) is a type. Vector!(float, 3) is a type. Vector is not. Vector is a template for a type. When you use a template, you instantiate it for a particular set of arguments, and that creates a new type. An instantiation of a templated type such as Vector is a type, and every instantiation is its own, separate type which has no connection with any other instantion of that template. So, it makes no sense for a function to take a Vector (though within the Vector template that works, because Vector stands for that particular instantiation inside of the Vector template). If you want a function to take multiple instantiations of a template, then you need to templatize the function. If you want it to take a particular instantiation of a template, then you give its parameter that exact template instantiation. Now, if you want two separate instantions (such as Vector!(int, 3) and Vector! (float, 3)) to interact, you're going to need to either write opCasts to cast between them or have templated functions which are templated on both of their types (e.g. func(V1, V2)(V1 vector1, V2 vector2) {...}). They are two completed different types, just like if you created IntVector and FloatVector, so you have to write code which allows them to interact. They aren't going to just work together because they came from the same template. - Jonathan M Davis
-- Yep, I'm afraid that I have a blog : zardoz.es
Jul 01 2011
prev sibling parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Fri, 01 Jul 2011 01:39:53 +0200, Zardoz <luis.panadero gmail.com> wrote:

 I have a parametrized struct (Vector!(T, dim)) that takes two parameters
 (Type and a number). And made some Alias with defaults parameters.

 In other struct (Matrix!(T, dim)), that uses these struct to represent a
 matrix in column-major order. I have a internall alias for Vector using
 internally (alias Vector!(T,dim_) VCol;) . The problem that I have it's
 when I try to use opIndexAssign to assign to a column a Vector. I try
 this :

 void opIndexAssign(Vector v, size_t j) {
 	if ( code that see if VCol if same type that v ) {
 		col[j] = v;
 	} else {
 		col[j] = cast (VCol) v;
 	}
 }

 But not compile... I get this error :
 Error: struct zmath.vector.Vector(T,ulong dim_) if (__traits
 (isFloating,T)) is used as a type
 Error: template instance zmath.matrix.Matrix!(float,2) error  
 instantiating

 So finally I try this :
 /**
 * Assigns a new column vector
 */
 void opIndexAssign(VCol v, size_t j) {
 	col[j] = v;
 }

 But now I must do cast outside, even knowing that are same type. Plus now
 I must keep VCol alias public.

 How should fix this, or What is the correct way of doing this ?
Private symbols in D are visible outside the defining module (and private symbols are accessible inside the same module), so having the alias private is no problem. In other words, the latter solution is good, and should not require any casting or public alias. Or have I perhaps misunderstood? Is there some other reason you need to cast? Also, the error message you get (Vector(...) is used as a type) is indicative of your referring to the Vector template rather than an instantiation. Struct templates in D behave as if defined thusly: template Foo( T ) { struct Foo { } } for a struct Foo( T ).
 Note : I have a opCast for Vector that cast between Vectors with
 different parameters and it's checked that works.

 Second Question : I'm thinking publish this small Vector/Quaternion/
 Matrix lib that I made learning D2.. where I should put and how ? (and I
 use Git)
GitHub, then? Or dsource.org. -- Simen
Jun 30 2011
parent reply Zardoz <luis.panadero gmail.com> writes:
Well, the problem is that I must do the cast always, see :

// alias Matrix!(real,4) Mat4r;
// alias Vector!(float, 3) Vec3f;
// alias Vector!(real, 4) Vec4r;
// In Mat4r, VCol it's aliased to Vector!(real, 4)

auto tcol = Mat4r.IDENTITY; 

auto v = cast(tcol.VCol) Vec3f(1, 2 ,3 ); 
auto v2 = Vec4r(-1, -2 ,-3 ,-4);

tcol[1] = v2; // Do a compiler error
tcol[2] = v;

I get this error :
Error: function zmath.matrix.Matrix!(real,4).Matrix.opIndexAssign (real 
c, ulong row, ulong cl) is not callable using argument types (Vector!
(real,4),int)
Error: cannot implicitly convert expression (v2) of type Vector!(real,4) 
to Vector!(real,dim)

If I do cast(tcol.Vcol) to v2, this works.
Plus if I do a typeid(v1), typeid(v2) to see his types, I get this :
zmath.vector.Vector!(real,4).Vector  zmath.vector.Vector!(real,dim).Vector

On Fri, 01 Jul 2011 02:29:58 +0200, Simen Kjaeraas wrote:
 On Fri, 01 Jul 2011 01:39:53 +0200, Zardoz <luis.panadero gmail.com>
 wrote:
 
 I have a parametrized struct (Vector!(T, dim)) that takes two
 parameters (Type and a number). And made some Alias with defaults
 parameters.

 In other struct (Matrix!(T, dim)), that uses these struct to represent
 a matrix in column-major order. I have a internall alias for Vector
 using internally (alias Vector!(T,dim_) VCol;) . The problem that I
 have it's when I try to use opIndexAssign to assign to a column a
 Vector. I try this :

 void opIndexAssign(Vector v, size_t j) {
 	if ( code that see if VCol if same type that v ) {
 		col[j] = v;
 	} else {
 		col[j] = cast (VCol) v;
 	}
 }

 But not compile... I get this error : Error: struct
 zmath.vector.Vector(T,ulong dim_) if (__traits (isFloating,T)) is used
 as a type
 Error: template instance zmath.matrix.Matrix!(float,2) error
 instantiating

 So finally I try this :
 /**
 * Assigns a new column vector
 */
 void opIndexAssign(VCol v, size_t j) {
 	col[j] = v;
 }

 But now I must do cast outside, even knowing that are same type. Plus
 now I must keep VCol alias public.

 How should fix this, or What is the correct way of doing this ?
Private symbols in D are visible outside the defining module (and private symbols are accessible inside the same module), so having the alias private is no problem. In other words, the latter solution is good, and should not require any casting or public alias. Or have I perhaps misunderstood? Is there some other reason you need to cast? Also, the error message you get (Vector(...) is used as a type) is indicative of your referring to the Vector template rather than an instantiation. Struct templates in D behave as if defined thusly: template Foo( T ) { struct Foo { } } for a struct Foo( T ).
 Note : I have a opCast for Vector that cast between Vectors with
 different parameters and it's checked that works.

 Second Question : I'm thinking publish this small Vector/Quaternion/
 Matrix lib that I made learning D2.. where I should put and how ? (and
 I use Git)
GitHub, then? Or dsource.org.
-- Yep, I'm afraid that I have a blog : zardoz.es
Jun 30 2011
parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Fri, 01 Jul 2011 08:58:32 +0200, Zardoz <luis.panadero gmail.com> wrote:

 Well, the problem is that I must do the cast always, see :

 // alias Matrix!(real,4) Mat4r;
 // alias Vector!(float, 3) Vec3f;
 // alias Vector!(real, 4) Vec4r;
 // In Mat4r, VCol it's aliased to Vector!(real, 4)

 auto tcol = Mat4r.IDENTITY;

 auto v = cast(tcol.VCol) Vec3f(1, 2 ,3 );
 auto v2 = Vec4r(-1, -2 ,-3 ,-4);

 tcol[1] = v2; // Do a compiler error
 tcol[2] = v;
So more likely, this is what you want: void opIndexAssign(U)(Vector!(U,dim) v, size_t j) { static if (is(U == T)) { col[j] = v; } else { col[j] = cast(VCol)v; } } -- Simen
Jul 01 2011
parent reply Zardoz <luis.panadero gmail.com> writes:
Finally I try this small test code :

struct A(T, int U) {
	T x;
	static enum foo = U;
	
	Tout opCast( Tout ) () 
	if (isA!Tout)	{
		Tout nt;
		nt.x = x;
		return nt;
	}
	
	string toString() {
		return to!string(x);
	}
}

struct B(T, int I) {
	enum foo2 = I;
	
	alias A!(T, foo2) Internal;
	
	Internal[foo2 * 2] y;
	
	void opIndexAssign(K) (K v, size_t j) 
	if (isA!(K) && K.foo == Internal.foo && is(typeof(K.x) == typeof(y[0].x)) ) {
		y[j] = v;
	}
		
	void opIndexAssign(K) (K v, size_t j) 
	if (isA!(K) && (K.foo != Internal.foo || !is(typeof(K.x) == typeof(y[0].x))) )
{
		y[j] = Internal(v.x);
	}

}

template isA(T) {
  immutable bool isA = __traits(compiles,
        (){  
            T t;
            auto x = t.x;
            auto u = t.foo;     
        }
    );
}


auto bla = A!(int, 2) (10);
auto bla2 =A!(int, 5) (5)
	
B!(int, 3) bleh;
	
bleh[1] = bla;	
bleh[3] = bla2;

writeln(bleh.y);

And write : [0, 10, 0, 5, 0, 0]

So this works. Only I need to discover why when I try it over Vector 
and Matrix class, I get errors...

Finally, I upload to github : git://github.com/Zardoz89/zmath.git
I hope that I not write some barbaric thing in my code.... 
I do all self-learning D

On Fri, 01 Jul 2011 17:19:36 +0200, Simen Kjaeraas wrote:

 On Fri, 01 Jul 2011 08:58:32 +0200, Zardoz <luis.panadero gmail.com>
 wrote:
 
 Well, the problem is that I must do the cast always, see :

 // alias Matrix!(real,4) Mat4r;
 // alias Vector!(float, 3) Vec3f;
 // alias Vector!(real, 4) Vec4r;
 // In Mat4r, VCol it's aliased to Vector!(real, 4)

 auto tcol = Mat4r.IDENTITY;

 auto v = cast(tcol.VCol) Vec3f(1, 2 ,3 ); auto v2 = Vec4r(-1, -2 ,-3
 ,-4);

 tcol[1] = v2; // Do a compiler error
 tcol[2] = v;
So more likely, this is what you want: void opIndexAssign(U)(Vector!(U,dim) v, size_t j) { static if (is(U == T)) { col[j] = v; } else { col[j] = cast(VCol)v; } }
-- Yep, I'm afraid that I have a blog : zardoz.es
Jul 01 2011
parent Zardoz <luis.panadero gmail.com> writes:
Ok, I fixed it. I just need to put (K) type parameter to the other opIndexAssign

D not allow overload operators/methods with different type parameters. 
They must share same type parameters :

void opIndexAssign(K)(K c, size_t row, size_t cl) {... }

void opIndexAssign(K) (K v, size_t j) { ... }

On Fri, 01 Jul 2011 21:46:56 +0000, Zardoz wrote:

 Finally I try this small test code :
 
 struct A(T, int U) {
 	T x;
 	static enum foo = U;
 	
 	Tout opCast( Tout ) ()
 	if (isA!Tout)	{
 		Tout nt;
 		nt.x = x;
 		return nt;
 	}
 	
 	string toString() {
 		return to!string(x);
 	}
 }
 
 struct B(T, int I) {
 	enum foo2 = I;
 	
 	alias A!(T, foo2) Internal;
 	
 	Internal[foo2 * 2] y;
 	
 	void opIndexAssign(K) (K v, size_t j) if (isA!(K) && K.foo ==
 	Internal.foo && is(typeof(K.x) == typeof(y[0].x)) ) {
 		y[j] = v;
 	}
 		
 	void opIndexAssign(K) (K v, size_t j) if (isA!(K) && (K.foo !=
 	Internal.foo || !is(typeof(K.x) == typeof(y[0].x))) ) {
 		y[j] = Internal(v.x);
 	}
 
 }
 
 template isA(T) {
   immutable bool isA = __traits(compiles,
         (){
             T t;
             auto x = t.x;
             auto u = t.foo;
         }
     );
 }
 
 
 auto bla = A!(int, 2) (10);
 auto bla2 =A!(int, 5) (5)
 	
 B!(int, 3) bleh;
 	
 bleh[1] = bla;
 bleh[3] = bla2;
 
 writeln(bleh.y);
 
 And write : [0, 10, 0, 5, 0, 0]
 
 So this works. Only I need to discover why when I try it over Vector and
 Matrix class, I get errors...
 
 Finally, I upload to github : git://github.com/Zardoz89/zmath.git I hope
 that I not write some barbaric thing in my code.... I do all
 self-learning D
 
 On Fri, 01 Jul 2011 17:19:36 +0200, Simen Kjaeraas wrote:
 
 On Fri, 01 Jul 2011 08:58:32 +0200, Zardoz <luis.panadero gmail.com>
 wrote:
 
 Well, the problem is that I must do the cast always, see :

 // alias Matrix!(real,4) Mat4r;
 // alias Vector!(float, 3) Vec3f;
 // alias Vector!(real, 4) Vec4r;
 // In Mat4r, VCol it's aliased to Vector!(real, 4)

 auto tcol = Mat4r.IDENTITY;

 auto v = cast(tcol.VCol) Vec3f(1, 2 ,3 ); auto v2 = Vec4r(-1, -2 ,-3
 ,-4);

 tcol[1] = v2; // Do a compiler error
 tcol[2] = v;
So more likely, this is what you want: void opIndexAssign(U)(Vector!(U,dim) v, size_t j) { static if (is(U == T)) { col[j] = v; } else { col[j] = cast(VCol)v; } }
-- Yep, I'm afraid that I have a blog : zardoz.es
Jul 01 2011