www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to Instantiate struct defined in template

reply "Craig Dillabaugh" <cdillaba cg.scs.carleton.ca> writes:
Hello,
I am trying to figure out how templates work and tried to define
the
following template to define vertices of any dimension and
operations
on them.

import std.stdio;
import std.random;
import std.range;
import std.conv;
import std.math;

/*
   * T must be one of the floating point types
   *   float, double, real _ I should be enforcing this.
   */
template  vt(T)
{
    struct vertex {
      this(T[] crds...) {
        if( crds.length < 2 ) {
          throw new.Exception("To small!");
        } else {
	coords.length = crds.length;
	foreach(ref v_coord, in_coord; lockstep(coords, crds))
	{
	  v_coord = in_coord;
	}
        }
      }
       property T x() { return coords[0];}
       property T y() { return coords[1];}
       property T z() { return ( coords.length < 3 ? T.nan :
coords[2] ); }
    }
	
    T euclid_dist(T a, T b) {
      T sum = 0;
      foreach( ref a_crd, ref b_crd; lockstep( a.coords, b.coords )
) {
        sum += (a_crd - b_crd)*(a_crd - b_crd );
      }
      return sqrt(sum);
    }
} //End of template

int main(string argv[] ) {
	vt!(float).vertex v1(0.0,0.0);
	vt!(float).vertex v2(3.0,4.0);
	writefln("The distance between vertex 1 and vertex 2 is ",
		vt!(float).euclid_dist(v1, v2) );
}

When I try to compile this I get the message:

vertex.d(57): Error: found 'v1' when expecting ';' following
statement
vertex.d(58): Error: found 'v2' when expecting ';' following
statement

Lines 57 and 58 are the first two lines in my main() function. I
can't figure out why, from the examples I've looked at I am using
the syntax properly, but am clearly missing something.

Also, since I don't really know what I am doing any criticisms on
how I am defining the vertex template are welcome.

Cheers,

Craig
Sep 22 2012
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, September 23, 2012 05:49:06 Craig Dillabaugh wrote:
 Hello,
 I am trying to figure out how templates work and tried to define
 the
 following template to define vertices of any dimension and
 operations
 on them.
 
 import std.stdio;
 import std.random;
 import std.range;
 import std.conv;
 import std.math;
 
 /*
    * T must be one of the floating point types
    *   float, double, real _ I should be enforcing this.
    */
 template  vt(T)
 {
     struct vertex {
       this(T[] crds...) {
         if( crds.length < 2 ) {
           throw new.Exception("To small!");
         } else {
 	coords.length = crds.length;
 	foreach(ref v_coord, in_coord; lockstep(coords, crds))
 	{
 	  v_coord = in_coord;
 	}
         }
       }
        property T x() { return coords[0];}
        property T y() { return coords[1];}
        property T z() { return ( coords.length < 3 ? T.nan :
 coords[2] ); }
     }
 
     T euclid_dist(T a, T b) {
       T sum = 0;
       foreach( ref a_crd, ref b_crd; lockstep( a.coords, b.coords )
 ) {
         sum += (a_crd - b_crd)*(a_crd - b_crd );
       }
       return sqrt(sum);
     }
 } //End of template
 
 int main(string argv[] ) {
 	vt!(float).vertex v1(0.0,0.0);
 	vt!(float).vertex v2(3.0,4.0);
 	writefln("The distance between vertex 1 and vertex 2 is ",
 		vt!(float).euclid_dist(v1, v2) );
 }
 
 When I try to compile this I get the message:
 
 vertex.d(57): Error: found 'v1' when expecting ';' following
 statement
 vertex.d(58): Error: found 'v2' when expecting ';' following
 statement
 
 Lines 57 and 58 are the first two lines in my main() function. I
 can't figure out why, from the examples I've looked at I am using
 the syntax properly, but am clearly missing something.
 
 Also, since I don't really know what I am doing any criticisms on
 how I am defining the vertex template are welcome.
Before anything, I'd question why you declared vt at all. If all you're putting in it is a single struct, then just templatize the struct directly: struct Vertex(T) { ... } Now, it looks like you have a free function in there as well - euclid_dist - but there's no reason to put that in the same template. Just templatize it directly. Then you get T euclid_dist(T)(T a, T b) {...} And main ends up looking something like void main() { auto v1 = Vertex!float(0.0, 0.0); auto v2 = Vertex!float(2.0, 4.0); writefln("The distance between vertex 1 and vertex 2 is %s", euclid_dist(v1, v2)); } It's actually fairly to explicitly declare a template in D outside of eponymous templates. If you're dealing with a user-defined type or function, it almost always makes more sense to templatize them directly. Now, as for the exact error message, it's because the syntax that you're using to define v1 and v2 is illegal. You'd need to do either vt!float.vertex v1 = vt!float(0.0, 0.0); or preferrably. auto v1 = vt!float(0.0, 0.0); You can't construct the type on the left-hand side of the assignment operator like that. - Jonathan M Davis
Sep 22 2012
parent reply "Craig Dillabaugh" <cdillaba cg.scs.carleton.ca> writes:
On Sunday, 23 September 2012 at 04:03:28 UTC, Jonathan M Davis
wrote:
 On Sunday, September 23, 2012 05:49:06 Craig Dillabaugh wrote:
 Hello,
clip
 Before anything, I'd question why you declared vt at all. If 
 all you're
 putting in it is a single struct, then just templatize the 
 struct directly:

 struct Vertex(T)
 {
     ...
 }

 Now, it looks like you have a free function in there as well - 
 euclid_dist -
 but there's no reason to put that in the same template. Just 
 templatize it
 directly. Then you get

 T euclid_dist(T)(T a, T b) {...}

 And main ends up looking something like

 void main()
 {
     auto v1 = Vertex!float(0.0, 0.0);
     auto v2 = Vertex!float(2.0, 4.0);
     writefln("The distance between vertex 1 and vertex 2 is %s",
              euclid_dist(v1, v2));
 }
Thanks. I've switched my code to follow your suggestion. One thing there was a typo in my euclid_dist function, the code for it, and main now look like: T euclid_dist(T)(vertex!T a, vertex!T b) { T sum = 0; foreach( ref a_crd, ref b_crd; lockstep( a.coords, b.coords ) ) { sum += (a_crd - b_crd)*(a_crd - b_crd ); } return sqrt(sum); } int main(string argv[] ) { auto v1 = vertex!float(0.0,0.0); auto v2 = vertex!float(3.0,4.0); writeln("The distance between vertex 1 and vertex 2 is ", euclid_dist!float(v1, v2) ); return 0; } One question. Is there any way to get the function template to deduce the type of T from the vertices I pass, so that I can call: euclid_dist(v1, v2) ) instead of: euclid_dist!float(v1, v2) );
 It's actually fairly to explicitly declare a template in D 
 outside of
 eponymous templates. If you're dealing with a user-defined type 
 or function, it
 almost always makes more sense to templatize them directly.

 Now, as for the exact error message, it's because the syntax 
 that you're using
 to define v1 and v2 is illegal. You'd need to do either

 vt!float.vertex v1 = vt!float(0.0, 0.0);

 or preferrably.

 auto v1 = vt!float(0.0, 0.0);

 You can't construct the type on the left-hand side of the 
 assignment operator
 like that.

 - Jonathan M Davis
,
Sep 22 2012
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, September 23, 2012 06:37:30 Craig Dillabaugh wrote:
 One question. Is there any way to get the function template to
 deduce the type of T from the vertices I pass, so that I can
 call:
 
 euclid_dist(v1, v2) )
 
 instead of:
 
 euclid_dist!float(v1, v2) );
It should infer the types just fine as-is. Templated functions can pretty much always infer the template arguments from their function arguments. It's with types that that doesn't work (so a constructor requires template arguments, but a function does not). - Jonathan M Davis
Sep 22 2012
parent "Craig Dillabaugh" <cdillaba cg.scs.carleton.ca> writes:
On Sunday, 23 September 2012 at 04:51:31 UTC, Jonathan M Davis
wrote:
 On Sunday, September 23, 2012 06:37:30 Craig Dillabaugh wrote:
 One question. Is there any way to get the function template to
 deduce the type of T from the vertices I pass, so that I can
 call:
 
 euclid_dist(v1, v2) )
 
 instead of:
 
 euclid_dist!float(v1, v2) );
It should infer the types just fine as-is. Templated functions can pretty much always infer the template arguments from their function arguments. It's with types that that doesn't work (so a constructor requires template arguments, but a function does not). - Jonathan M Davis
Yes, you are right. I thought I had tried it without the !float and it hadn't worked, but I guess not. Thanks again for all your help. Craig
Sep 22 2012