On Sat, 08 Oct 2011 03:52:25 -0700, Roderick Gibson wrote: > On 10/7/2011 11:35 PM, Ali Çehreli wrote: >> 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 > > 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...)
I didn't know that would work. :) > but 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