www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - templated type reduction

reply EntangledQuanta <EQ universe.com> writes:
Suppose one had the need to template a something like

struct X(T)
{
    string type = T.stringof;
    T t;
}


But one needs to get the type to know how to interpret X!T but 
one only has a void* to a type X!T. That is, we know it is an "X" 
but we don't know the specific T.

Now, this is easy as X!void or X!int or adding any specific but 
arbitrary type T, if the value we want is not dependent T... but 
in this case it is:


void* x = new X!int;

(passed around the program)

switch(x.type)
{
     case "int" : break;
}

which is invalid yet perfectly valid! Is there any way to make 
this work legitly in D? I could get the offset of the string then 
parse it, but that's a hack I'd rather not use and isn't really 
safe(change the order and it will break).

note that it is really no different from

struct X(T)
{
    string type = "asdf";
    T t;
}

in which we can do

string type = (cast(X!int)x).type; // = asdf

or

string type = (cast(X!float)x).type; // = asdf

but even this is a bit fishy.


Heres some code that does the offset hack:


struct X(T)
{
	string type = T.stringof;
	T x;
}

int main(string[] args)
{

	void* x = new X!int;

	int o = (X!float).type.offsetof;
	auto y = *cast(string*)(x + o);
	writeln(y);
	return 0;
}
Sep 02 2017
next sibling parent EntangledQuanta <EQ universe.com> writes:
I should point out that I know it isn't safe in some cases(I 
already mentioned about the order mattering in some cases) but in 
that case a compiler error could be thrown. It's safe in some 
cases and I have the ability to create a safe case since I'm the 
designer of the code(e.g., put things in correct order).
Sep 02 2017
prev sibling parent ag0aep6g <anonymous example.com> writes:
On 09/02/2017 11:07 PM, EntangledQuanta wrote:
 struct X(T)
 {
     string type = T.stringof;
     T t;
 }
[...]
 void* x = new X!int;
 
 (passed around the program)
 
 switch(x.type)
 {
      case "int" : break;
 }
 
 which is invalid yet perfectly valid! Is there any way to make this work 
 legitly in D?
Not with `void*`, I think. `void*` explicitly tells the compiler to forget anything it knows about the type. You could make a new type `struct XBase { string type; }` and use `XBase*` instead of `void*`. If you're going to `new` the instances anyway, classes could also help: ---- class XBase { string type; } class X(T) : XBase { T t; } ---- [...]
 note that it is really no different from
 
 struct X(T)
 {
     string type = "asdf";
     T t;
 }
 
 in which we can do
 
 string type = (cast(X!int)x).type; // = asdf
 
 or
 
 string type = (cast(X!float)x).type; // = asdf
 
 but even this is a bit fishy.
I think this is the best you can do with `void*`. Maybe add an assert in X that checks that the field `type` is always at the same offset (0).
 Heres some code that does the offset hack:
 
 
 struct X(T)
 {
      string type = T.stringof;
      T x;
 }
 
 int main(string[] args)
 {
 
      void* x = new X!int;
 
      int o = (X!float).type.offsetof;
      auto y = *cast(string*)(x + o);
      writeln(y);
      return 0;
 }
I don't think `.offsetof` buys you anything over `(cast(X!int)x).type`. By the way, `void main()` is valid. You don't need to return 0 or declare `args` if you don't use them.
Sep 02 2017