digitalmars.D.learn - Is there a way to set an alias to specific form of a template?
- Roderick Gibson (21/21) Oct 07 2011 This may be the completely wrong approach, but I am basically thinking
- Andrej Mitrovic (11/11) Oct 07 2011 You don't have to rewrite Vector for multiple dimensions, methinks:
- Roderick Gibson (24/35) Oct 07 2011 I got this working, found an odd bug though. This code,
-
Philippe Sigaud
(32/54)
Oct 08 2011
On Sat, Oct 8, 2011 at 08:43, Roderick Gibson
wrote: - Andrej Mitrovic (2/2) Oct 08 2011 I would go with Ali =C7ehreli's example instead of the variadic type
- Andrej Mitrovic (3/3) Oct 07 2011 There's an LGPL-licensed Vector module here:
- Roderick Gibson (3/6) Oct 07 2011 Awesome, thanks for both answers. I figured there was already an
- bearophile (4/8) Oct 08 2011 Eventually Phobos will contain fast 2D/3D/4D vector type, because they a...
- Ali =?iso-8859-1?q?=C7ehreli?= (26/53) Oct 07 2011 You can take advantage of 'Template Value Parameters' and 'Typesafe
- Roderick Gibson (13/67) Oct 08 2011 I decided this would be the best way, thank you. One question though, I
- Ali =?iso-8859-1?q?=C7ehreli?= (69/150) Oct 08 2011 Here is some ugly code that accepts either T[N] or N Ts. Note that the
This may be the completely wrong approach, but I am basically thinking of something like this (I am aware this will not compile, it's psuedocode): class Vector(T) { ... //definition here } alias Vector(float, float) vec2f; auto v = new vec2f(1.0,1.0); I am making a templated Vector class (a mathematical vector) that will have varying types (thus a template) and dimensions (via variadic functions), so that the same template definition will work for 2d or 3d vectors (or 4d, etc). I then want the programmer to be able to define the specific forms that he wants so he can easily keep track of them (without getting confused about which is a 2d integer vector and which is a 3d float vector), and then use those forms in a type safe manner. Is this even possible? If it is, but it's the wrong way to do it, what's the right way? Basically I wanted to write it once and not worry about writing it again to handle different types and dimensions (no vec2i class, or vec2f, or vec3f, or vec3i, etc). Templates easily handles the type requirement, but what about the dimensional requirement? Am I just going to have to rewrite it when I add dimensions?
Oct 07 2011
You don't have to rewrite Vector for multiple dimensions, methinks: class Vector(T...) { this(T t) {} } void main() { alias Vector!(float, float) vec2f; auto v = new vec2f(1.0,1.0); } You'll probably have to play with `static if`, template constraints, and stuff like that.
Oct 07 2011
On 10/7/2011 7:33 PM, Andrej Mitrovic wrote:You don't have to rewrite Vector for multiple dimensions, methinks: class Vector(T...) { this(T t) {} } void main() { alias Vector!(float, float) vec2f; auto v = new vec2f(1.0,1.0); } You'll probably have to play with `static if`, template constraints, and stuff like that.I got this working, found an odd bug though. This code, alias Vector!(float, float) vec2f; alias Vector!(double, double) vec2d; alias Vector!(float, float, float) vec3f; public struct Vector(T...) { int dim = 0; this(T...)(T args) { dim = args.length; } unittest { auto v = new vec2f(1.2f, 1.5f); vec2f d = new vec2f(1.1f, 1.4f); assert(v.dim == 2); assert(d.dim == 2); } } will pass the first assert and fail on the second. Checking out the contents of v.length and d.length with writeln gives the correct answer on the first and 2 1 RANDOMHEXCODE on the second. Very strange.
Oct 07 2011
On Sat, Oct 8, 2011 at 08:43, Roderick Gibson <kniteli gmail.com> wrote: A possible problem (or feature ?) with the Vector(T...) code is that you could possibly create a Vector!(int, float, string), for example. Even with template constraints to limit the inner types to numerical types, this template has too much freedom, I think : Vector!(float, int, short) is a strange type for a vector. I'd go the Vector(Type, int length) way myself. Or even Matrix(Type, nRows, nCol) or somesuch.I got this working, found an odd bug though. This code, alias Vector!(float, float) vec2f; alias Vector!(double, double) vec2d; alias Vector!(float, float, float) vec3f; public struct Vector(T...) { =C2=A0 =C2=A0 =C2=A0 =C2=A0int dim =3D 0; =C2=A0 =C2=A0 =C2=A0 =C2=A0this(T...)(T args) { =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0dim =3D args.lengt=h;=C2=A0 =C2=A0 =C2=A0 =C2=A0} =C2=A0 =C2=A0 =C2=A0 =C2=A0unittest { =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0auto v =3D new vec=2f(1.2f, 1.5f);=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0vec2f d =3D new ve=c2f(1.1f, 1.4f);=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0assert(v.dim =3D==3D 2);=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0assert(d.dim =3D==3D 2);} will pass the first assert and fail on the second. Checking out the conte=ntsof v.length and d.length with writeln gives the correct answer on the fir=stand 2 1 RANDOMHEXCODE on the second. Very strange.You Vector is a struct, a value type in D. Do not 'new' structs, as you'd do in C++ (in D, you'll use new only for classes or reference types in general) Given a struct S, new S() has type S*. I think in: vec2f d =3D new vec2f(...); You create a vec2f and try to assign a vec2f* to it. Try this, it should work: =C2=A0 =C2=A0 =C2=A0 =C2=A0unittest { =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0auto v =3D vec2f(1= .2f, 1.5f); =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0vec2f d =3D vec2f(= 1.1f, 1.4f); =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0assert(v.dim =3D=3D= 2); =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0assert(d.dim =3D=3D= 2); }
Oct 08 2011
I would go with Ali =C7ehreli's example instead of the variadic type example I gave, I think it could simplify code quite a bit.
Oct 08 2011
There's an LGPL-licensed Vector module here: https://github.com/Zardoz89/zmath/blob/master/src/vector.d Not mine, but it's interesting.
Oct 07 2011
On 10/7/2011 7:37 PM, Andrej Mitrovic wrote:There's an LGPL-licensed Vector module here: https://github.com/Zardoz89/zmath/blob/master/src/vector.d Not mine, but it's interesting.Awesome, thanks for both answers. I figured there was already an implementation, this is mostly just to play with/learn templates :)
Oct 07 2011
Andrej Mitrovic:There's an LGPL-licensed Vector module here: https://github.com/Zardoz89/zmath/blob/master/src/vector.d Not mine, but it's interesting.Eventually Phobos will contain fast 2D/3D/4D vector type, because they are used often in games, programs that need 2D geometry, various simulations, etc. Bye, bearophile
Oct 08 2011
On Fri, 07 Oct 2011 18:29:26 -0700, Roderick Gibson wrote:This may be the completely wrong approach, but I am basically thinking of something like this (I am aware this will not compile, it's psuedocode): class Vector(T) { ... //definition here } alias Vector(float, float) vec2f; auto v = new vec2f(1.0,1.0); I am making a templated Vector class (a mathematical vector) that will have varying types (thus a template) and dimensions (via variadic functions), so that the same template definition will work for 2d or 3d vectors (or 4d, etc). I then want the programmer to be able to define the specific forms that he wants so he can easily keep track of them (without getting confused about which is a 2d integer vector and which is a 3d float vector), and then use those forms in a type safe manner. Is this even possible? If it is, but it's the wrong way to do it, what's the right way? Basically I wanted to write it once and not worry about writing it again to handle different types and dimensions (no vec2i class, or vec2f, or vec3f, or vec3i, etc). Templates easily handles the type requirement, but what about the dimensional requirement? Am I just going to have to rewrite it when I add dimensions?You can take advantage of 'Template Value Parameters' and 'Typesafe Variadic Functions': http://www.d-programming-language.org/ template.html#TemplateValueParameter http://www.d-programming-language.org/function.html class Vector(T, int N) { T[N] elements; this(T[] elements ...) { this.elements = elements; } } alias Vector!(double, 2) Vec2D; alias Vector!(double, 3) Vec3D; void main() { auto v2d = new Vec2D(2.2, 2.2); auto v3d = new Vec3D(3.3, 3.3, 3.3); // Alternatively, all parameters at once: auto v3d_too = new Vec3D([ 33, 33, 33, ]); } (Some would find 'size_t N' to be more appropriate since N is a dimension.) Ali
Oct 07 2011
On 10/7/2011 11:35 PM, Ali Çehreli wrote:On Fri, 07 Oct 2011 18:29:26 -0700, Roderick Gibson wrote:I decided this would be the best way, thank you. One question though, I noticed with this method that you can only assert that the dimension and the parameter list length match at runtime (ie, someone could instantiate a vec2d as vec2d(2.2, 2.2, 3.1) and the compiler will happily accept it), I'm guessing constraints are what's needed, but I don't know how to get the parameter count at compile time, only at runtime (via elements.length). The compiler *should* know the length at compile time shouldn't it? I managed to get it to at least stop the compilation with this(T[N] elements...) but the error messages are terrible. Is there a better way, perhaps using a static assert?This may be the completely wrong approach, but I am basically thinking of something like this (I am aware this will not compile, it's psuedocode): class Vector(T) { ... //definition here } alias Vector(float, float) vec2f; auto v = new vec2f(1.0,1.0); I am making a templated Vector class (a mathematical vector) that will have varying types (thus a template) and dimensions (via variadic functions), so that the same template definition will work for 2d or 3d vectors (or 4d, etc). I then want the programmer to be able to define the specific forms that he wants so he can easily keep track of them (without getting confused about which is a 2d integer vector and which is a 3d float vector), and then use those forms in a type safe manner. Is this even possible? If it is, but it's the wrong way to do it, what's the right way? Basically I wanted to write it once and not worry about writing it again to handle different types and dimensions (no vec2i class, or vec2f, or vec3f, or vec3i, etc). Templates easily handles the type requirement, but what about the dimensional requirement? Am I just going to have to rewrite it when I add dimensions?You can take advantage of 'Template Value Parameters' and 'Typesafe Variadic Functions': http://www.d-programming-language.org/ template.html#TemplateValueParameter http://www.d-programming-language.org/function.html class Vector(T, int N) { T[N] elements; this(T[] elements ...) { this.elements = elements; } } alias Vector!(double, 2) Vec2D; alias Vector!(double, 3) Vec3D; void main() { auto v2d = new Vec2D(2.2, 2.2); auto v3d = new Vec3D(3.3, 3.3, 3.3); // Alternatively, all parameters at once: auto v3d_too = new Vec3D([ 33, 33, 33, ]); } (Some would find 'size_t N' to be more appropriate since N is a dimension.) Ali
Oct 08 2011
On Sat, 08 Oct 2011 03:52:25 -0700, Roderick Gibson wrote:On 10/7/2011 11:35 PM, Ali Çehreli wrote:I didn't know that would work. :)On Fri, 07 Oct 2011 18:29:26 -0700, Roderick Gibson wrote:I decided this would be the best way, thank you. One question though, I noticed with this method that you can only assert that the dimension and the parameter list length match at runtime (ie, someone could instantiate a vec2d as vec2d(2.2, 2.2, 3.1) and the compiler will happily accept it), I'm guessing constraints are what's needed, but I don't know how to get the parameter count at compile time, only at runtime (via elements.length). The compiler *should* know the length at compile time shouldn't it? I managed to get it to at least stop the compilation with this(T[N] elements...)This may be the completely wrong approach, but I am basically thinking of something like this (I am aware this will not compile, it's psuedocode): class Vector(T) { ... //definition here } alias Vector(float, float) vec2f; auto v = new vec2f(1.0,1.0); I am making a templated Vector class (a mathematical vector) that will have varying types (thus a template) and dimensions (via variadic functions), so that the same template definition will work for 2d or 3d vectors (or 4d, etc). I then want the programmer to be able to define the specific forms that he wants so he can easily keep track of them (without getting confused about which is a 2d integer vector and which is a 3d float vector), and then use those forms in a type safe manner. Is this even possible? If it is, but it's the wrong way to do it, what's the right way? Basically I wanted to write it once and not worry about writing it again to handle different types and dimensions (no vec2i class, or vec2f, or vec3f, or vec3i, etc). Templates easily handles the type requirement, but what about the dimensional requirement? Am I just going to have to rewrite it when I add dimensions?You can take advantage of 'Template Value Parameters' and 'Typesafe Variadic Functions': http://www.d-programming-language.org/ template.html#TemplateValueParameter http://www.d-programming-language.org/function.html class Vector(T, int N) { T[N] elements; this(T[] elements ...) { this.elements = elements; } } alias Vector!(double, 2) Vec2D; alias Vector!(double, 3) Vec3D; void main() { auto v2d = new Vec2D(2.2, 2.2); auto v3d = new Vec3D(3.3, 3.3, 3.3); // Alternatively, all parameters at once: auto v3d_too = new Vec3D([ 33, 33, 33, ]); } (Some would find 'size_t N' to be more appropriate since N is a dimension.) Alibut the error messages are terrible. Is there a better way, perhaps using a static assert?Here is some ugly code that accepts either T[N] or N Ts. Note that the constructor now takes T[N], not T[N]...: import std.stdio; import std.string; import std.conv; string ctor_with_params(T, int N)() { string param_list; foreach (i; 0 .. N) { if (i != 0) { param_list ~= ", "; } param_list ~= T.stringof ~ " p" ~ to!string(i); } string code = "this(" ~ param_list ~ ") { elements = [ " ; foreach (i; 0 .. N) { if (i != 0) { code ~= ", "; } code ~= "p" ~ to!string(i); } code ~= " ]; }"; return code; } unittest { writeln(ctor_with_params!(double, 3)()); } class Vector(T, int N) { T[N] elements; this(T[N] elements) { this.elements = elements; } mixin(ctor_with_params!(T, N)()); } alias Vector!(double, 3) Vec3D; void main() { auto v0 = new Vec3D( 33, 33, 33, ); auto v1 = new Vec3D([ 33, 33, 33, ]); /* Error: constructor deneme.Vector!(double,3).Vector.this (double[3LU] elements) is not callable using argument types (int,int) */ // auto v2 = new Vec3D( 33, 33 ); /* Error: constructor deneme.Vector!(double,3).Vector.this (double[3LU] elements) is not callable using argument types (int[]) Error: cannot implicitly convert expression ([33,33,33,33]) of type int[] to double Error: expected 3 function arguments, not 1 */ // auto v3 = new Vec3D([ 33, 33, 33, 33 ]); } It prints the mixed-in N-parameter constructor: this(double p0, double p1, double p2) { elements = [ p0, p1, p2 ]; } If you don't need the T[N] constructor at all, the best approach could be removing it. Then the error messages make more sense: class Vector(T, int N) { T[N] elements; mixin(ctor_with_params!(T, N)()); } Ali
Oct 08 2011