Nested Structs (Solution)
js.mdnq
js_adddot+mdng at gmail.com
Wed Dec 12 14:16:19 PST 2012
Here is a solution I came up with that seems to work fine and
does not require hard coding any values. Hence, it is useable.
Unfortunately it looks clunky and is: (and it would be nice to
speed up the the method call and possible code it in such a way
that if D directly supports this in the future it will be easy to
update)
http://dpaste.dzfl.pl/64025e0a
The idea is rather simple: We pass the offset of the struct
object to itself as a template parameter. This allows the struct
to calculate where it is at relative to the parent, which then
allows it to access the members of the parent. This is quite easy
to do and no issue. (except, of course, copying the struct will
potentially invalidate it's parent)
The problem is actually calculating the offsets of these structs
in the class(which are passed to the struct). Hard coding is a no
go and using offsetof will not work because of forward
referencing(you need to know the size of the type to find out the
offsets
To do this, kinda hackish, but works, is we template the class
containing the structs. This allows us to conditionally create
the class. A!0, creates a class that we can then use to get the
offsets. The forward references are no longer since we use A!0
which passes dummy offsets to the structs. A!x, for x > 0, then
calculates the offsets of the structs using A!0 as a blueprint.
A!0 has no offsetof so no forward referencing. A!1 uses offsetof
for A!0, so, again, no forward referencing. Since passing offsets
do not change the size we should expect A!1 to have the layout as
A!0.
The "trick" here is:
static if (dummy == 0) B!(0) b1; else B!(A.b1.offsetof) b1;
As you can see in the code, it's quite messy and ideally should
look like a normal nested struct inside a class without any
template parameters being used.
I'm hoping someone can come up with an elegant way to wrap this
neatly into a package that can be used as any normal nested
struct, or close.
Thanks...
Code:
module main;
import std.stdio;
class cAt(int dummy)
{
alias cAt!0 A;
struct B(int ofs) {
int Value;
A Parent()
{
auto p = cast(void *)&this - ofs;
return cast(A)(p);
}
}
static if (dummy == 0) B!(0) b1; else B!(A.b1.offsetof) b1;
static if (dummy == 0) B!(0) b2; else B!(A.b2.offsetof) b2;
string Name;
this()
{
Name = "Class";
}
}
alias cAt!1 A;
int main(string[] argv)
{
auto asize = A.classinfo.init.length;
auto bsize = A.B!(0).sizeof;
A a = new A();
auto x = a.b1.Parent();
auto y = a.b2.Parent();
auto s1 = A.init.b1.offsetof;
auto s2 = A.init.b2.offsetof;
auto a_ptr = cast(void*)a;
auto x_ptr = cast(void*)x;
auto y_ptr = cast(void*)y;
assert(a_ptr == x_ptr);
assert(x_ptr == y_ptr);
getchar();
return 0;
}
More information about the Digitalmars-d
mailing list