www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Array initialization with Struct templates

reply "WhatMeWorry" <kheaser gmail.com> writes:
This seemingly trivial array initialization has caused me hours 
of grief.

enum Purpose { POSITIONAL, COLOR_ONLY, COLOR_AND_ALPHA, 
GENERIC_TRIPLE, GENERIC_QUAD }
Purpose purpose;

struct Chameleon(T, Purpose p)  // template
{
     static if (is (p == POSITIONAL)) {
         T  x, y, z;
     } else static if (is (p == COLOR_ONLY)) {
         T  r, g, b;
     } else static if (is (p == COLOR_AND_ALPHA)) {
         T  r, g, b, a;
     }  else static if (is (p == GENERIC_TRIPLE)) {
         T  a, b, c;
     } else static if (is (p == GENERIC_QUAD)) {
         T  a, b, c, d;
     }
};

struct VertexData
{
     Chameleon!(float, purpose.POSITIONAL)  position;
     Chameleon!(float, purpose.COLOR_ONLY)  color;
}

alias Vert = VertexData;

VertexData[] vertices =
[
     Vert(1.0, 1.0, 1.0, 0.0, 0.0, 0.0)  // compiler error here
];

I keep getting:

Error: cannot implicitly convert expression (1.00000) of type 
double to Chameleon!(double, cast(Purpose)0)	

I even tried  Vert(1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f)

but it has the exact same error.  Any ideas?  Thanks in advance.
Aug 30 2015
parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Monday, August 31, 2015 04:57:05 WhatMeWorry via Digitalmars-d-learn wrote:
 This seemingly trivial array initialization has caused me hours
 of grief.

 enum Purpose { POSITIONAL, COLOR_ONLY, COLOR_AND_ALPHA,
 GENERIC_TRIPLE, GENERIC_QUAD }
 Purpose purpose;

 struct Chameleon(T, Purpose p)  // template
 {
      static if (is (p == POSITIONAL)) {
          T  x, y, z;
      } else static if (is (p == COLOR_ONLY)) {
          T  r, g, b;
      } else static if (is (p == COLOR_AND_ALPHA)) {
          T  r, g, b, a;
      }  else static if (is (p == GENERIC_TRIPLE)) {
          T  a, b, c;
      } else static if (is (p == GENERIC_QUAD)) {
          T  a, b, c, d;
      }
 };

 struct VertexData
 {
      Chameleon!(float, purpose.POSITIONAL)  position;
      Chameleon!(float, purpose.COLOR_ONLY)  color;
 }

 alias Vert = VertexData;

 VertexData[] vertices =
 [
      Vert(1.0, 1.0, 1.0, 0.0, 0.0, 0.0)  // compiler error here
 ];

 I keep getting:

 Error: cannot implicitly convert expression (1.00000) of type
 double to Chameleon!(double, cast(Purpose)0)

 I even tried  Vert(1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f)

 but it has the exact same error.  Any ideas?  Thanks in advance.
VertexData doesn't have a constructor that takes 6 doubles or 6 floats. It has a compiler-generated constructor that's equivalent to this(Chameleon!(float, purpose.POSITIONAL) position, Chameleon!(float, purpose.COLOR_ONLY) color) { this.position = position; this.color = color; } So, you're going to need to pass it a Chameleon!(float, purpose.POSITIONAL) and a Chameleon!(float, purpose.COLOR_ONLY color), not 6 doubles - either that, or you're going to need to declare a constructor for VertexData which takes 6 doubles or floats and converts them to what's require to assign to its member variables. - Jonathan M Davis
Aug 30 2015
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/30/2015 10:38 PM, Jonathan M Davis via Digitalmars-d-learn wrote:
 On Monday, August 31, 2015 04:57:05 WhatMeWorry via Digitalmars-d-learn wrote:
 This seemingly trivial array initialization has caused me hours
 of grief.

 enum Purpose { POSITIONAL, COLOR_ONLY, COLOR_AND_ALPHA,
 GENERIC_TRIPLE, GENERIC_QUAD }
 Purpose purpose;

 struct Chameleon(T, Purpose p)  // template
 {
       static if (is (p == POSITIONAL)) {
           T  x, y, z;
       } else static if (is (p == COLOR_ONLY)) {
           T  r, g, b;
       } else static if (is (p == COLOR_AND_ALPHA)) {
           T  r, g, b, a;
       }  else static if (is (p == GENERIC_TRIPLE)) {
           T  a, b, c;
       } else static if (is (p == GENERIC_QUAD)) {
           T  a, b, c, d;
       }
 };

 struct VertexData
 {
       Chameleon!(float, purpose.POSITIONAL)  position;
       Chameleon!(float, purpose.COLOR_ONLY)  color;
 }

 alias Vert = VertexData;

 VertexData[] vertices =
 [
       Vert(1.0, 1.0, 1.0, 0.0, 0.0, 0.0)  // compiler error here
 ];

 I keep getting:

 Error: cannot implicitly convert expression (1.00000) of type
 double to Chameleon!(double, cast(Purpose)0)

 I even tried  Vert(1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f)

 but it has the exact same error.  Any ideas?  Thanks in advance.
VertexData doesn't have a constructor that takes 6 doubles or 6 floats. It has a compiler-generated constructor that's equivalent to this(Chameleon!(float, purpose.POSITIONAL) position, Chameleon!(float, purpose.COLOR_ONLY) color) { this.position = position; this.color = color; } So, you're going to need to pass it a Chameleon!(float, purpose.POSITIONAL) and a Chameleon!(float, purpose.COLOR_ONLY color), not 6 doubles - either that, or you're going to need to declare a constructor for VertexData which takes 6 doubles or floats and converts them to what's require to assign to its member variables. - Jonathan M Davis
Additionally, the OP uses the is expression which compares the equality of types. However, 'Purpose p' is a value template parameter. A simple == comparison works: enum Purpose { POSITIONAL, COLOR_ONLY, COLOR_AND_ALPHA, GENERIC_TRIPLE, GENERIC_QUAD } Purpose purpose; struct Chameleon(T, Purpose p) // template { static if (p == Purpose.POSITIONAL) { // <-- NOT is expression T x, y, z; } else static if (p == Purpose.COLOR_ONLY) { T r, g, b; } else static if (p == Purpose.COLOR_AND_ALPHA) { T r, g, b, a; } else static if (p == Purpose.GENERIC_TRIPLE) { T a, b, c; } else static if (p == Purpose.GENERIC_QUAD) { T a, b, c, d; } }; struct VertexData { Chameleon!(float, purpose.POSITIONAL) position; Chameleon!(float, purpose.COLOR_ONLY) color; } alias Vert = VertexData; VertexData[] vertices = [ Vert(Chameleon!(float, purpose.POSITIONAL)(1.0f, 1.0f, 1.0f), Chameleon!(float, purpose.COLOR_ONLY)(0.0, 0.0, 0.0)) ]; void main() {}
Aug 30 2015
parent "Mike Parker" <aldacron gmail.com> writes:
On Monday, 31 August 2015 at 05:47:31 UTC, Ali Çehreli wrote:
 On 08/30/2015 10:38 PM, Jonathan M Davis via 
 Digitalmars-d-learn wrote:
 On Monday, August 31, 2015 04:57:05 WhatMeWorry via 
 Digitalmars-d-learn wrote:
 This seemingly trivial array initialization has caused me 
 hours
 of grief.

 enum Purpose { POSITIONAL, COLOR_ONLY, COLOR_AND_ALPHA,
 GENERIC_TRIPLE, GENERIC_QUAD }
 Purpose purpose;

 struct Chameleon(T, Purpose p)  // template
 {
       static if (is (p == POSITIONAL)) {
           T  x, y, z;
       } else static if (is (p == COLOR_ONLY)) {
           T  r, g, b;
       } else static if (is (p == COLOR_AND_ALPHA)) {
           T  r, g, b, a;
       }  else static if (is (p == GENERIC_TRIPLE)) {
           T  a, b, c;
       } else static if (is (p == GENERIC_QUAD)) {
           T  a, b, c, d;
       }
 };

 struct VertexData
 {
       Chameleon!(float, purpose.POSITIONAL)  position;
       Chameleon!(float, purpose.COLOR_ONLY)  color;
 }

 alias Vert = VertexData;

 VertexData[] vertices =
 [
       Vert(1.0, 1.0, 1.0, 0.0, 0.0, 0.0)  // compiler error 
 here
 ];
I would drop chameleon all together and just add the fields directly to VertexData, but make Purpose flag-based. enum Purpose { position = 0x00, // Assuming all verts have a position colorOnly = 0x01, colorAlpha = 0x02, triple = 0x04, quad = 0x08 } enum hasColorOnly(Purpose p) = (p & Purpose.colorOnly) == Purpose.colorOnly; struct VertexData(T, Purpose purpose){ T x, y, z; static if(hasColorOnly!purpose) T r, g, b; ... } Then you can templatize your batches or meshes, or whatever you use to represent vertex objects, on the VertexData type. alias ColorVertexf = VertexData!(float, Purpose.colorOnly); auto batch = new Batch!(ColorVertexf);
Aug 30 2015
prev sibling parent reply "Daniel N" <ufo orbiting.us> writes:
On Monday, 31 August 2015 at 05:38:54 UTC, Jonathan M Davis wrote:
 So, you're going to need to pass it a Chameleon!(float, 
 purpose.POSITIONAL) and a Chameleon!(float, purpose.COLOR_ONLY 
 color), not 6 doubles - either that, or you're going to need to 
 declare a constructor for VertexData which takes 6 doubles or 
 floats and converts them to what's require to assign to its 
 member variables.

 - Jonathan M Davis
Or turn Chameleon into a mixin template. enum Purpose { POSITIONAL, COLOR_ONLY, COLOR_AND_ALPHA, GENERIC_TRIPLE, GENERIC_QUAD } Purpose purpose; mixin template Chameleon(T, Purpose p) // mixin template { static if (p == Purpose.POSITIONAL) { // <-- NOT is expression T x, y, z; } else static if (p == Purpose.COLOR_ONLY) { T r, g, b; } else static if (p == Purpose.COLOR_AND_ALPHA) { T r, g, b, a; } else static if (p == Purpose.GENERIC_TRIPLE) { T a, b, c; } else static if (p == Purpose.GENERIC_QUAD) { T a, b, c, d; } }; struct VertexData { mixin Chameleon!(float, purpose.POSITIONAL) position; mixin Chameleon!(float, purpose.COLOR_ONLY) color; } alias Vert = VertexData; VertexData[] vertices = [ Vert(1.0f, 1.0f, 1.0f, 0.0, 0.0, 0.0), ]; void main() {}
Aug 31 2015
parent reply "WhatMeWorry" <kheaser gmail.com> writes:
Thanks for all the above suggestions, but after many hour of 
re-reading Ali's book on template, structs, and mixins, I still 
in the woods.  I've tried two approaches:

================ Templatetized struct 
================================

struct Chameleon(T, Purpose p)
{
     static if (p == Purpose.POSITIONAL)
     {
         struct Positional { T  x, y, z; }
     }
     else static if (p == Purpose.COLOR)
     {
         struct Color_No_Alpha { T  r, g, b; }
     }
};

struct VertexData
{
     Chameleon!(float, purpose.POSITIONAL)  position;
     Chameleon!(float, purpose.COLOR)  color;
}

alias Vert = VertexData;
alias Pos = VertexData.position;
alias RGB = VertexData.color;

VertexData[] vertices =
[
     VertexData( Pos(1.0, 1.0, 1.0), RGB(0.0, 0.0, 0.0))  // 
Compiler error
];

Error: struct Chameleon does not overload ()

Is this the overloading of the default constructor? Can't I use 
it?  I'm I calling it incorrectly?

	
======================  The Mixin Template approach 
===========================

mixin template Chameleon(T, Purpose p)
{
     static if (p == Purpose.POSITIONAL)
     {
         struct Positional { T  x, y, z; }
     }
     else static if (p == Purpose.COLOR)
     {
         struct Color_No_Alpha { T  r, g, b; }
     }
};

struct VertexData
{
     mixin Chameleon!(float, purpose.POSITIONAL)  position;
     mixin Chameleon!(float, purpose.COLOR)  color;
}

alias Vert = VertexData;
alias Pos = VertexData.position;
alias RGB = VertexData.color;

VertexData[] vertices =
[
     VertexData( Pos(1.0, 1.0, 1.0), RGB(0.0, 0.0, 0.0))
];

returns  Error: function expected before (), not mixin 
Chameleon!(float, cast(Purpose)0) position;

And like above, I'm clueless.
Aug 31 2015
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/31/2015 08:55 PM, WhatMeWorry wrote:

 Thanks for all the above suggestions, but after many hour of re-reading
 Ali's book on template, structs, and mixins, I still in the woods.  I've
 tried two approaches:

 ================ Templatetized struct ================================

 struct Chameleon(T, Purpose p)
 {
      static if (p == Purpose.POSITIONAL)
      {
          struct Positional { T  x, y, z; }
      }
      else static if (p == Purpose.COLOR)
      {
          struct Color_No_Alpha { T  r, g, b; }
      }
 };
(Aside: You don't need that semicolon in D.) So, you have a struct template that contains another struct type, either a Positional or a Color_No_Alpha. Note that the outer struct has no members at all: It merely defines two struct types. I can do the following but I don't think it's what you want: auto x = Chameleon!(float, Purpose.POSITIONAL).Positional(1.5, 2.5, 3.5);
 struct VertexData
 {
      Chameleon!(float, purpose.POSITIONAL)  position;
      Chameleon!(float, purpose.COLOR)  color;
 }
You have a couple of typos there: purpose should be capitalized. However, I see that you had the following in your original code: enum Purpose { POSITIONAL, COLOR_ONLY, COLOR_AND_ALPHA, GENERIC_TRIPLE, GENERIC_QUAD } Purpose purpose; // ... Chameleon!(float, purpose.POSITIONAL) position; I am surprised that it works! Must be a "feature". ;) The common thing to do is to remove the 'purpose' variable and use the enum type directly: enum Purpose { /* ... */ } // ... Chameleon!(float, Purpose.POSITIONAL) position;
 alias Vert = VertexData;
Fine.
 alias Pos = VertexData.position;
 alias RGB = VertexData.color;
Those two don't make sense because both .position and .color are member variables. If you did the following, then we would be talking about the types of those members: alias Pos = typeof(VertexData.position); alias RGB = typeof(VertexData.color);
 VertexData[] vertices =
 [
      VertexData( Pos(1.0, 1.0, 1.0), RGB(0.0, 0.0, 0.0))  // Compiler 
error
 ];
However, that won't work because Chameleon does not have any members. The same with the mixin template... I am copying my earlier code with a couple of aliases to make closer to yours: enum Purpose { POSITIONAL, COLOR_ONLY } struct Chameleon(T, Purpose p) { static if (p == Purpose.POSITIONAL) { T x, y, z; } else static if (p == Purpose.COLOR_ONLY) { T r, g, b; } else { static assert(false, "Not yet supported"); } } alias Pos = Chameleon!(float, Purpose.POSITIONAL); alias Color = Chameleon!(float, Purpose.COLOR_ONLY); struct VertexData { Pos position; Color color; } alias Vert = VertexData; VertexData[] vertices = [ Vert(Pos(1.0f, 1.0f, 1.0f), Color(0.0, 0.0, 0.0)) ]; void main() {} Ali
Aug 31 2015