Re: Reflection in game engine (c++)
Will Vale <[email protected]> Fri, 15 Mar 2013 13:32:23 +1300
| Newsgroups | gmane.games.devel.sweng |
|---|---|
| Message-ID | <CAEV+7KD9anynhmFRqoiNvqCim=s-FF65ePYNX4OjYmY+tkkekQ@mail.gmail.com> |
--===============0473400601==
Content-Type: multipart/alternative; boundary=20cf30363f75dfba9204d7ebc5cd
--20cf30363f75dfba9204d7ebc5cd
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
I've tried a few versions of #1 over the years, and the thing that always
bugged me was repetition - I really don't like it when you have to
duplicate types in the member definitions. I also (having tried it) wanted
to avoid deriving from a common base class to get reflection features. And
finally I didn't want to use templates to actually work with reflected
objects - I'd rather sacrifice a bit of compile-time proveability for not
generating N versions of things.
My current take on this has the usual DECLARE macro in the header for
compound types:
struct Ingredient{ SIL_RTTI_COMPOUND(Ingredient, void) // No
base union { /// Type of the facet,
stored as a hash Nat hash; /// System
implementing this facet mutable ISystem *system;
} type; /// Constant data for the facet, which can be re-used
by different entities const void *data; /// Where to
place the facet w.r.t. the entity Location offset; ///
Anchor facet indices Nat8 anchors[MAX_ANCHORS];};
and looks like this in the source file:
SIL_RTTI(sil::game::Ingredient, SIL_MEMBER(type.hash)
SIL_MEMBER(data) SIL_MEMBER(offset) SIL_MEMBER(anchors))
(Templates deduce types for members.)
This generates an instance of a class derived from rtti::IType, of
which there are a small hierarchy representing different kinds of C++
type - atoms, compounds, pointers, C arrays etc. When you work with
arbitrary reflected instances you get a void pointer and an IType
reference, and write bespoke code to walk the types and members to
achieve something. It usually looks like this so it's not quite as
scary as void* would suggest:
// Generic code
void really_do_stuff(const rtti::IType& type, void *instance)
{
// Inspect type and do things with *instance
}
// Type-safe layer which gets compiled away - Type<T>() (usually) gets
compiled to "load address of type data"
template <typename T> void do_stuff(T& object)
{
really_do_stuff(rtti::Type<T>(), &object);
}
The code you write in really_do_stuff can get a bit boilerplate-ey,
but you don't have to do it often, and there are ways of reducing the
boilerplate (iterator, visitor) which can be layered on top. I've
generally found it easier to write the code out rather than coerce it
into the iterator's view though. Here's a (small extract) of real code
which constructs objects from text definitions:
static void build_compound( const PropertyTree::Group& group, const
rtti::ICompoundType &type, void *instance, Librarian& librarian )
{ for ( const rtti::ICompoundType *t =3D &type; t; t=3D t->Base() )
{ for ( Nat m =3D 0; m !=3D t->MemberCount(); ++m )
{ const
rtti::ICompoundType::Member& member =3D t->GetMember(m);
// Lookup once (smaller code, more wasteful runtime)
const PropertyTree::Group* member_group =3D
group.FindGroup(member.Name()); const
PropertyTree::Property *member_prop =3D
group.FindProperty(member.Name()); // Handle
member's type build_instance(member_group,
member_prop, member.Type(), OffsetPtr(instance, member.offset),
librarian); } instance =3D
OffsetPtr(instance, t->BaseOffset()); }}
This kind of thing doesn't get used at runtime, but it's used in tools
to build "memory image"-style data files which are used at runtime.
Loading these uses a pinch of reflection for calling constructors etc,
but it's not much.
The nice thing about this (and other variations of #1) is that if it
ends up not working you can switch to #4 without re-annotating your
source :)
Will
On Fri, Mar 15, 2013 at 12:40 PM, Nathan Martz <[email protected]>wrote=
:
> We use something very similar to what Adrian describes on his blog here a=
t
> DF. The syntax is a bit different, but I=92d definitely vouch taking an
> approach like the one Adrian describes. One really great upside of this
> type of solution is that done right, there=92s not much boilerplate at al=
l
> and you get the benefit of the entire system being implemented in code th=
at
> you own and know. Building solutions off of heavy weight tools like CLANG
> or a big lexer or whatever may open up big long term opportunities and
> eventually minimize the amount of =93boilerplate=94 someone needs to writ=
e, but
> it requires you (and anyone who will extend or maintain the system) to
> develop deep knowledge of some seriously complex software, so much so tha=
t
> it may make the investment prohibitive.****
>
> ** **
>
> -Nathan****
>
> ** **
>
> *From:* [email protected] [mailto:
> [email protected]] *On Behalf Of *Adrian Ston=
e
> *Sent:* Thursday, March 14, 2013 4:29 PM
> *To:* [email protected]
> *Subject:* Re: [Sweng-Gamedev] Reflection in game engine (c++)****
>
> ** **
>
> ** **
>
> I=92m not sure which number describes our approach, but we=92ve been usin=
g it
> for about 8 years on many different projects and I believe everyone on th=
e
> team has been very happy with it. I=92ve written about it pretty extensi=
vely
> here: http://gameangst.com/?p=3D107****
>
> ** **
>
> There are some implementation details I=92d change if I were starting ove=
r
> from scratch, but I still think that using advanced C++ features to creat=
e
> an embedded DSL is the best option for reflection in C++.****
>
> ** **
>
> Adrian****
>
> ** **
>
> ** **
> ------------------------------
>
> *From:* [email protected] [
> mailto:[email protected]<sweng-gamedev-bounce=
[email protected]>]
> *On Behalf Of *Alen Ladavac
> *Sent:* Thursday, March 14, 2013 6:45 PM
> *To:* Gabriel Sassone
> *Cc:* [email protected];
> [email protected]
> *Subject:* Re: [Sweng-Gamedev] Reflection in game engine (c++)****
>
> ** **
>
> We've been using #4 in our projects for a decade already and it works a
> treat. And... why couldn't you invoke methods? :)
>
> That method is the only really fully portable (AFAIK), as it doesn't
> really care what compiler/toolset you have. It is also very light in term=
s
> of runtime requirements, and very easy to use (not much extra typing for
> each class, member or function).
>
> Though it is rather involved to implement.
>
> JM2C,
> Alen
>
> Thursday, March 14, 2013, 7:09:30 PM, you wrote:****
>
> ** **
>
> Hello gents,
> I wanted to experiment with reflection and I found different way to
> obtain it:
>
> 1) Invasive macro based registration
> 2) Reflection visitor pattern
> 3) Parsing pdb/clang stuff and create a manual table of what you
> want/need
> 4) c++ custom parser that uses tags to create reflection informations
> (like a comment near a member, ...) (exuberant ctags???)
> 5) create serializable/reflected classes in a data format, then run a
> tool that generates headers and cpps
>
> I am trying to figure out flaws and merits of each kind, and even if ther=
e
> are other solutions.
> I love the idea to have the possibility to serialize in and out
> structures, access fields and change values, stream in/out stuff from
> network ,and maybe link with scripting.
>
> My goal is to have fast iteration times, both artists and programmers, an=
d
> I achieved it for rendering programmers already with having json binarize=
d
> configurable rendering, but still there are code stuff that are not easy =
to
> achieve.
>
> Here are my thoughts, but I would like to hear your ideas and experiences=
!
>
> 1) Very precise on what you can register/serialize, but painful to
> maintain or plug into an existing codebase
> 2) Less precise but you just need one method per class, that you can use
> to serialize/reflect. Still bad in maintaining, but better in plugging in=
.
> 3) You make the compiler do the work, then translate the informations you
> need in your format. Easy to maintain, to plug...maybe slow in parsing?
> Slow your build pipeline?
> 4) maybe easier than using pdbs, but less powerful (you cannot invoke
> methods on objects). should be faster than 3.
> 5) crazy idea. requires generation of code from outside...powerful like 4=
,
> so data reflection, but you cannot invoke methods if you want.
>
> What are your experiences/thoughts?
>
> Thanks to everyone that read this mail!
>
> Gabriel****
>
>
>
>
>
> *--
> Best regards,
> Alen *mailto:[email protected]<alenl-ml@cr=
oteam.com>
> ****
>
> _______________________________________________
> Sweng-Gamedev mailing list
> [email protected]
> http://lists.midnightryder.com/listinfo.cgi/sweng-gamedev-midnightryder.c=
om
>
>
--20cf30363f75dfba9204d7ebc5cd
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">I've tried a few versions of #1 over the years, and th=
e thing that always bugged me was repetition - I really don't like it w=
hen you have to duplicate types in the member definitions. I also (having t=
ried it) wanted to avoid deriving from a common base class to get reflectio=
n features. And finally I didn't want to use templates to actually work=
with reflected objects - I'd rather sacrifice a bit of compile-time pr=
oveability for not generating N versions of things.<div>
<br></div><div style>My current take on this has the usual DECLARE macro in=
the header for compound types:<br></div><div><br></div><div><pre style=3D"=
font-family:'Bitstream Vera Sans Mono','DejaVu Sans Mono',M=
onaco,monospace;font-size:12px;line-height:1.4;margin-top:0px;margin-bottom=
:0px;color:rgb(51,51,51)">
<span style=3D"color:rgb(0,64,128)">struct</span> <span>Ingredient</span>
<a name=3D"13d6b62697aca4ec_cl-17" style=3D"color:rgb(59,115,175)"></a><spa=
n>{</span>
<a name=3D"13d6b62697aca4ec_cl-18" style=3D"color:rgb(59,115,175)"></a> =
<span>SIL_RTTI_COMPOUND</span><span>(</span><span>Ingredient</span><spa=
n>,</span> <span style=3D"color:rgb(68,85,136)">void</span><span>) // No ba=
se</span>
<a name=3D"13d6b62697aca4ec_cl-19" style=3D"color:rgb(59,115,175)"></a>
<a name=3D"13d6b62697aca4ec_cl-20" style=3D"color:rgb(59,115,175)"></a> =
<span style=3D"color:rgb(0,64,128)">union</span>
<a name=3D"13d6b62697aca4ec_cl-21" style=3D"color:rgb(59,115,175)"></a> =
<span>{</span>
<a name=3D"13d6b62697aca4ec_cl-22" style=3D"color:rgb(59,115,175)"></a> =
<span style=3D"color:rgb(153,153,136);font-style:italic">/// Ty=
pe of the facet, stored as a hash</span>
<a name=3D"13d6b62697aca4ec_cl-23" style=3D"color:rgb(59,115,175)"></a> =
<span>Nat</span> <span>hash</span><span>;</span>
<a name=3D"13d6b62697aca4ec_cl-24" style=3D"color:rgb(59,115,175)"></a>
<a name=3D"13d6b62697aca4ec_cl-25" style=3D"color:rgb(59,115,175)"></a> =
<span style=3D"color:rgb(153,153,136);font-style:italic">/// Sy=
stem implementing this facet</span>
<a name=3D"13d6b62697aca4ec_cl-26" style=3D"color:rgb(59,115,175)"></a> =
<span>mutable</span> <span>ISystem</span> <span>*</span><span>s=
ystem</span><span>;</span>
<a name=3D"13d6b62697aca4ec_cl-27" style=3D"color:rgb(59,115,175)"></a>
<a name=3D"13d6b62697aca4ec_cl-28" style=3D"color:rgb(59,115,175)"></a> =
<span>}</span> <span>type</span><span>;</span>
<a name=3D"13d6b62697aca4ec_cl-29" style=3D"color:rgb(59,115,175)"></a>
<a name=3D"13d6b62697aca4ec_cl-30" style=3D"color:rgb(59,115,175)"></a> =
<span style=3D"color:rgb(153,153,136);font-style:italic">/// Constant d=
ata for the facet, which can be re-used by different entities</span>
<a name=3D"13d6b62697aca4ec_cl-31" style=3D"color:rgb(59,115,175)"></a> =
<span style=3D"color:rgb(0,64,128)">const</span> <span style=3D"color:r=
gb(68,85,136)">void</span> <span>*</span><span>data</span><span>;</span>
<a name=3D"13d6b62697aca4ec_cl-32" style=3D"color:rgb(59,115,175)"></a>
<a name=3D"13d6b62697aca4ec_cl-33" style=3D"color:rgb(59,115,175)"></a> =
<span style=3D"color:rgb(153,153,136);font-style:italic">/// Where to p=
lace the facet w.r.t. the entity</span>
<a name=3D"13d6b62697aca4ec_cl-34" style=3D"color:rgb(59,115,175)"></a> =
<span>Location</span> <span>offset</span><span>;</span>
<a name=3D"13d6b62697aca4ec_cl-35" style=3D"color:rgb(59,115,175)"></a>
<a name=3D"13d6b62697aca4ec_cl-36" style=3D"color:rgb(59,115,175)"></a> =
<span style=3D"color:rgb(153,153,136);font-style:italic">/// Anchor fac=
et indices</span>
<a name=3D"13d6b62697aca4ec_cl-37" style=3D"color:rgb(59,115,175)"></a> =
<span>Nat8</span> <span>anchors</span><span>[</span><span>MAX_ANCHORS</=
span><span>];</span>
<span>};</span></pre></div><div><br></div><div>and looks like this in the s=
ource file:</div><div><div><br></div><div><pre style=3D"font-family:'Bi=
tstream Vera Sans Mono','DejaVu Sans Mono',Monaco,monospace;fon=
t-size:12px;line-height:1.4;margin-top:0px;margin-bottom:0px;color:rgb(51,5=
1,51)">
<span>SIL_RTTI</span><span>(</span><span>sil</span><span>::</span><span>gam=
e</span><span>::</span><span>Ingredient</span><span>,</span>=20
<a name=3D"13d6b62697aca4ec_cl-11" style=3D"color:rgb(59,115,175)"></a> =
<span>SIL_MEMBER</span><span>(</span><span>type</span><span>.</span><sp=
an>hash</span><span>)</span>
<a name=3D"13d6b62697aca4ec_cl-12" style=3D"color:rgb(59,115,175)"></a> =
<span>SIL_MEMBER</span><span>(</span><span>data</span><span>)</span>
<a name=3D"13d6b62697aca4ec_cl-13" style=3D"color:rgb(59,115,175)"></a> =
<span>SIL_MEMBER</span><span>(</span><span>offset</span><span>)</span>
<a name=3D"13d6b62697aca4ec_cl-14" style=3D"color:rgb(59,115,175)"></a> =
<span>SIL_MEMBER</span><span>(</span><span>anchors</span><span>)</span>
<a name=3D"13d6b62697aca4ec_cl-15" style=3D"color:rgb(59,115,175)"></a><spa=
n>)</span></pre><pre style=3D"font-family:'Bitstream Vera Sans Mono'=
;,'DejaVu Sans Mono',Monaco,monospace;font-size:12px;line-height:1.=
4;margin-top:0px;margin-bottom:0px;color:rgb(51,51,51)">
<br></pre><pre style=3D"font-family:'Bitstream Vera Sans Mono','=
;DejaVu Sans Mono',Monaco,monospace;font-size:12px;line-height:1.4;marg=
in-top:0px;margin-bottom:0px;color:rgb(51,51,51)">(Templates deduce types f=
or members.)</pre>
<pre style=3D"font-family:'Bitstream Vera Sans Mono','DejaVu Sa=
ns Mono',Monaco,monospace;font-size:12px;line-height:1.4;margin-top:0px=
;margin-bottom:0px;color:rgb(51,51,51)"><br></pre><pre style=3D"font-family=
:'Bitstream Vera Sans Mono','DejaVu Sans Mono',Monaco,monos=
pace;font-size:12px;line-height:1.4;margin-top:0px;margin-bottom:0px;color:=
rgb(51,51,51)">
This generates an instance of a class derived from rtti::IType, of which th=
ere are a small hierarchy representing different kinds of C++ type - atoms,=
compounds, pointers, C arrays etc. When you work with arbitrary reflected =
instances you get a void pointer and an IType reference, and write bespoke =
code to walk the types and members to achieve something.=A0It usually looks=
like this so it's not quite as scary as void* would suggest:</pre>
<pre style=3D"font-family:'Bitstream Vera Sans Mono','DejaVu Sa=
ns Mono',Monaco,monospace;font-size:12px;line-height:1.4;margin-top:0px=
;margin-bottom:0px;color:rgb(51,51,51)"><br></pre><pre style=3D"font-family=
:'Bitstream Vera Sans Mono','DejaVu Sans Mono',Monaco,monos=
pace;font-size:12px;line-height:1.4;margin-top:0px;margin-bottom:0px;color:=
rgb(51,51,51)">
// Generic code</pre><pre style=3D"font-family:'Bitstream Vera Sans Mon=
o','DejaVu Sans Mono',Monaco,monospace;font-size:12px;line-heig=
ht:1.4;margin-top:0px;margin-bottom:0px;color:rgb(51,51,51)">void really_do=
_stuff(const rtti::IType& type, void *instance)</pre>
<pre style=3D"font-family:'Bitstream Vera Sans Mono','DejaVu Sa=
ns Mono',Monaco,monospace;font-size:12px;line-height:1.4;margin-top:0px=
;margin-bottom:0px;color:rgb(51,51,51)">{</pre><pre style=3D"font-family:&#=
39;Bitstream Vera Sans Mono','DejaVu Sans Mono',Monaco,monospac=
e;font-size:12px;line-height:1.4;margin-top:0px;margin-bottom:0px;color:rgb=
(51,51,51)">
// Inspect type and do things with *instance</pre><pre style=3D"font-fa=
mily:'Bitstream Vera Sans Mono','DejaVu Sans Mono',Monaco,m=
onospace;font-size:12px;line-height:1.4;margin-top:0px;margin-bottom:0px;co=
lor:rgb(51,51,51)">
<span style=3D"line-height:1.4">}</span><br></pre><pre style=3D"font-family=
:'Bitstream Vera Sans Mono','DejaVu Sans Mono',Monaco,monos=
pace;font-size:12px;line-height:1.4;margin-top:0px;margin-bottom:0px;color:=
rgb(51,51,51)">
<br></pre><pre style=3D"font-family:'Bitstream Vera Sans Mono','=
;DejaVu Sans Mono',Monaco,monospace;font-size:12px;line-height:1.4;marg=
in-top:0px;margin-bottom:0px;color:rgb(51,51,51)">// Type-safe layer which =
gets compiled away - Type<T>() (usually) gets compiled to "load =
address of type data"</pre>
<pre style=3D"font-family:'Bitstream Vera Sans Mono','DejaVu Sa=
ns Mono',Monaco,monospace;font-size:12px;line-height:1.4;margin-top:0px=
;margin-bottom:0px;color:rgb(51,51,51)">template <typename T> void do=
_stuff(T& object) </pre>
<pre style=3D"font-family:'Bitstream Vera Sans Mono','DejaVu Sa=
ns Mono',Monaco,monospace;font-size:12px;line-height:1.4;margin-top:0px=
;margin-bottom:0px;color:rgb(51,51,51)">{</pre><pre style=3D"font-family:&#=
39;Bitstream Vera Sans Mono','DejaVu Sans Mono',Monaco,monospac=
e;font-size:12px;line-height:1.4;margin-top:0px;margin-bottom:0px;color:rgb=
(51,51,51)">
really_do_stuff(rtti::Type<T>(), &object);</pre><pre style=3D=
"font-family:'Bitstream Vera Sans Mono','DejaVu Sans Mono',=
Monaco,monospace;font-size:12px;line-height:1.4;margin-top:0px;margin-botto=
m:0px;color:rgb(51,51,51)">
}</pre><pre style=3D"font-family:'Bitstream Vera Sans Mono','De=
jaVu Sans Mono',Monaco,monospace;font-size:12px;line-height:1.4;margin-=
top:0px;margin-bottom:0px;color:rgb(51,51,51)"><br></pre><pre style=3D"font=
-family:'Bitstream Vera Sans Mono','DejaVu Sans Mono',Monac=
o,monospace;font-size:12px;line-height:1.4;margin-top:0px;margin-bottom:0px=
;color:rgb(51,51,51)">
The code you write in really_do_stuff can get a bit boilerplate-ey, but you=
don't have to do it often, and there are ways of reducing the boilerpl=
ate (iterator, visitor) which can be layered on top. I've generally fou=
nd it easier to write the code out rather than coerce it into the iterator&=
#39;s view though. Here's a (small extract) of real code which construc=
ts objects from text definitions:</pre>
<pre style=3D"font-family:'Bitstream Vera Sans Mono','DejaVu Sa=
ns Mono',Monaco,monospace;font-size:12px;line-height:1.4;margin-top:0px=
;margin-bottom:0px;color:rgb(51,51,51)"><br></pre><pre style=3D"font-family=
:'Bitstream Vera Sans Mono','DejaVu Sans Mono',Monaco,monos=
pace;font-size:12px;line-height:1.4;margin-top:0px;margin-bottom:0px;color:=
rgb(51,51,51)">
<span class=3D"" style=3D"line-height:1.4;color:rgb(0,64,128)">static</span=
><span style=3D"line-height:1.4"> </span><span class=3D"" style=3D"line-hei=
ght:1.4;color:rgb(68,85,136)">void</span><span style=3D"line-height:1.4"> <=
/span><span class=3D"" style=3D"line-height:1.4;color:rgb(153,0,0)">build_c=
ompound</span><span class=3D"" style=3D"line-height:1.4">(</span><span styl=
e=3D"line-height:1.4"> </span><span class=3D"" style=3D"line-height:1.4;col=
or:rgb(0,64,128)">const</span><span style=3D"line-height:1.4"> </span><span=
class=3D"" style=3D"line-height:1.4">PropertyTree</span><span class=3D"" s=
tyle=3D"line-height:1.4">::</span><span class=3D"" style=3D"line-height:1.4=
">Group</span><span class=3D"" style=3D"line-height:1.4">&</span><span =
style=3D"line-height:1.4"> </span><span class=3D"" style=3D"line-height:1.4=
">group</span><span class=3D"" style=3D"line-height:1.4">,</span><span styl=
e=3D"line-height:1.4"> </span><span class=3D"" style=3D"line-height:1.4;col=
or:rgb(0,64,128)">const</span><span style=3D"line-height:1.4"> </span><span=
class=3D"" style=3D"line-height:1.4">rtti</span><span class=3D"" style=3D"=
line-height:1.4">::</span><span class=3D"" style=3D"line-height:1.4">ICompo=
undType</span><span style=3D"line-height:1.4"> </span><span class=3D"" styl=
e=3D"line-height:1.4">&</span><span class=3D"" style=3D"line-height:1.4=
">type</span><span class=3D"" style=3D"line-height:1.4">,</span><span style=
=3D"line-height:1.4"> </span><span class=3D"" style=3D"line-height:1.4;colo=
r:rgb(68,85,136)">void</span><span style=3D"line-height:1.4"> </span><span =
class=3D"" style=3D"line-height:1.4">*</span><span class=3D"" style=3D"line=
-height:1.4">instance</span><span class=3D"" style=3D"line-height:1.4">,</s=
pan><span style=3D"line-height:1.4"> </span><span class=3D"" style=3D"line-=
height:1.4">Librarian</span><span class=3D"" style=3D"line-height:1.4">&=
;</span><span style=3D"line-height:1.4"> </span><span class=3D"" style=3D"l=
ine-height:1.4">librarian</span><span style=3D"line-height:1.4"> </span><sp=
an class=3D"" style=3D"line-height:1.4">)</span><br>
</pre><pre style=3D"font-family:'Bitstream Vera Sans Mono','Dej=
aVu Sans Mono',Monaco,monospace;font-size:12px;line-height:1.4;margin-t=
op:0px;margin-bottom:0px;color:rgb(51,51,51)"><pre style=3D"font-family:=
9;Bitstream Vera Sans Mono','DejaVu Sans Mono',Monaco,monospace=
;line-height:1.4;margin-top:0px;margin-bottom:0px">
<a name=3D"cl-89" style=3D"color:rgb(59,115,175)"></a><span class=3D"">{</s=
pan>
<a name=3D"cl-90" style=3D"color:rgb(59,115,175)"></a> <span class=
=3D"" style=3D"color:rgb(0,64,128)">for</span> <span class=3D"">(</span> <s=
pan class=3D"" style=3D"color:rgb(0,64,128)">const</span> <span class=3D"">=
rtti</span><span class=3D"">::</span><span class=3D"">ICompoundType</span> =
<span class=3D"">*</span><span class=3D"">t</span> <span class=3D"">=3D</sp=
an> <span class=3D"">&</span><span class=3D"">type</span><span class=3D=
"">;</span> <span class=3D"">t</span><span class=3D"">;</span> <span class=
=3D"">t</span><span class=3D"">=3D</span> <span class=3D"">t</span><span cl=
ass=3D"">-></span><span class=3D"">Base</span><span class=3D"">()</span>=
<span class=3D"">)</span>
<a name=3D"cl-91" style=3D"color:rgb(59,115,175)"></a> <span class=
=3D"">{</span>
<a name=3D"cl-92" style=3D"color:rgb(59,115,175)"></a> <span=
class=3D"" style=3D"color:rgb(0,64,128)">for</span> <span class=3D"">(</sp=
an> <span class=3D"">Nat</span> <span class=3D"">m</span> <span class=3D"">=
=3D</span> <span class=3D"" style=3D"color:rgb(0,153,153)">0</span><span cl=
ass=3D"">;</span> <span class=3D"">m</span> <span class=3D"">!=3D</span> <s=
pan class=3D"">t</span><span class=3D"">-></span><span class=3D"">Member=
Count</span><span class=3D"">();</span> <span class=3D"">++</span><span cla=
ss=3D"">m</span> <span class=3D"">)</span>
<a name=3D"cl-93" style=3D"color:rgb(59,115,175)"></a> <span=
class=3D"">{</span>
<a name=3D"cl-94" style=3D"color:rgb(59,115,175)"></a> =
<span class=3D"" style=3D"color:rgb(0,64,128)">const</span> <span class=
=3D"">rtti</span><span class=3D"">::</span><span class=3D"">ICompoundType</=
span><span class=3D"">::</span><span class=3D"">Member&</span> <span cl=
ass=3D"">member</span> <span class=3D"">=3D</span> <span class=3D"">t</span=
><span class=3D"">-></span><span class=3D"">GetMember</span><span class=
=3D"">(</span><span class=3D"">m</span><span class=3D"">);</span>
<a name=3D"cl-95" style=3D"color:rgb(59,115,175)"></a>
<a name=3D"cl-96" style=3D"color:rgb(59,115,175)"></a> =
<span class=3D"" style=3D"color:rgb(153,153,136);font-style:italic">// L=
ookup once (smaller code, more wasteful runtime)</span>
<a name=3D"cl-97" style=3D"color:rgb(59,115,175)"></a> =
<span class=3D"" style=3D"color:rgb(0,64,128)">const</span> <span class=
=3D"">PropertyTree</span><span class=3D"">::</span><span class=3D"">Group</=
span><span class=3D"">*</span> <span class=3D"">member_group</span> <span c=
lass=3D"">=3D</span> <span class=3D"">group</span><span class=3D"">.</span>=
<span class=3D"">FindGroup</span><span class=3D"">(</span><span class=3D"">=
member</span><span class=3D"">.</span><span class=3D"">Name</span><span cla=
ss=3D"">());</span>
<a name=3D"cl-98" style=3D"color:rgb(59,115,175)"></a> =
<span class=3D"" style=3D"color:rgb(0,64,128)">const</span> <span class=
=3D"">PropertyTree</span><span class=3D"">::</span><span class=3D"">Propert=
y</span> <span class=3D"">*</span><span class=3D"">member_prop</span> <span=
class=3D"">=3D</span> <span class=3D"">group</span><span class=3D"">.</spa=
n><span class=3D"">FindProperty</span><span class=3D"">(</span><span class=
=3D"">member</span><span class=3D"">.</span><span class=3D"">Name</span><sp=
an class=3D"">());</span>
<a name=3D"cl-99" style=3D"color:rgb(59,115,175)"></a>
<a name=3D"cl-100" style=3D"color:rgb(59,115,175)"></a> =
<span class=3D"" style=3D"color:rgb(153,153,136);font-style:italic">// =
Handle member's type</span>
<a name=3D"cl-101" style=3D"color:rgb(59,115,175)"></a> =
<span class=3D"">build_instance</span><span class=3D"">(</span><span cl=
ass=3D"">member_group</span><span class=3D"">,</span> <span class=3D"">memb=
er_prop</span><span class=3D"">,</span> <span class=3D"">member</span><span=
class=3D"">.</span><span class=3D"">Type</span><span class=3D"">(),</span>=
<span class=3D"">OffsetPtr</span><span class=3D"">(</span><span class=3D""=
>instance</span><span class=3D"">,</span> <span class=3D"">member</span><sp=
an class=3D"">.</span><span class=3D"">offset</span><span class=3D"">),</sp=
an> <span class=3D"">librarian</span><span class=3D"">);</span>
<a name=3D"cl-102" style=3D"color:rgb(59,115,175)"></a> <spa=
n class=3D"">}</span>
<a name=3D"cl-103" style=3D"color:rgb(59,115,175)"></a>
<a name=3D"cl-104" style=3D"color:rgb(59,115,175)"></a> <spa=
n class=3D"">instance</span> <span class=3D"">=3D</span> <span class=3D"">O=
ffsetPtr</span><span class=3D"">(</span><span class=3D"">instance</span><sp=
an class=3D"">,</span> <span class=3D"">t</span><span class=3D"">-></spa=
n><span class=3D"">BaseOffset</span><span class=3D"">());</span>
<a name=3D"cl-105" style=3D"color:rgb(59,115,175)"></a> <span class=
=3D"">}</span>
<a name=3D"cl-106" style=3D"color:rgb(59,115,175)"></a><span class=3D"">}</=
span></pre><pre style=3D"font-family:'Bitstream Vera Sans Mono',=
9;DejaVu Sans Mono',Monaco,monospace;line-height:1.4;margin-top:0px;mar=
gin-bottom:0px">
<span class=3D""><br></span></pre><pre style=3D"font-family:'Bitstream =
Vera Sans Mono','DejaVu Sans Mono',Monaco,monospace;line-height=
:1.4;margin-top:0px;margin-bottom:0px"><span style=3D"line-height:1.4">This=
kind of thing doesn't get used at runtime, but it's used in tools =
to build "memory image"-style data files which are used at runtim=
e. Loading these uses a pinch of reflection for calling constructors etc, b=
ut it's not much.</span><br>
</pre></pre>
<pre style=3D"font-family:'Bitstream Vera Sans Mono','DejaVu Sa=
ns Mono',Monaco,monospace;font-size:12px;line-height:1.4;margin-top:0px=
;margin-bottom:0px;color:rgb(51,51,51)"><br></pre><pre style=3D"font-family=
:'Bitstream Vera Sans Mono','DejaVu Sans Mono',Monaco,monos=
pace;font-size:12px;line-height:1.4;margin-top:0px;margin-bottom:0px;color:=
rgb(51,51,51)">
<span style=3D"line-height:1.4">The nice thing about this (and other variat=
ions of #1) is that if it ends up not working you can switch to #4 without =
re-annotating your source :)</span><br></pre><pre style=3D"font-family:'=
;Bitstream Vera Sans Mono','DejaVu Sans Mono',Monaco,monospace;=
font-size:12px;line-height:1.4;margin-top:0px;margin-bottom:0px;color:rgb(5=
1,51,51)">
<br></pre><pre style=3D"font-family:'Bitstream Vera Sans Mono','=
;DejaVu Sans Mono',Monaco,monospace;font-size:12px;line-height:1.4;marg=
in-top:0px;margin-bottom:0px;color:rgb(51,51,51)">Will
<a name=3D"13d6b62697aca4ec_cl-16" style=3D"color:rgb(59,115,175)"></a>
</pre></div></div></div><div class=3D"gmail_extra"><br><br><div class=3D"gm=
ail_quote">On Fri, Mar 15, 2013 at 12:40 PM, Nathan Martz <span dir=3D"ltr"=
><<a href=3D"mailto:[email protected]" target=3D"_blank">Nathan@doub=
lefine.com</a>></span> wrote:<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><div lang=3D"EN-US" link=3D"blue" vlink=3D"b=
lue"><div><p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-famil=
y:"Calibri","sans-serif";color:#1f497d">We use somethin=
g very similar to what Adrian describes on his blog here at DF. The syntax =
is a bit different, but I=92d definitely vouch taking an approach like the =
one Adrian describes. One really great upside of this type of solution is t=
hat done right, there=92s not much boilerplate at all and you get the benef=
it of the entire system being implemented in code that you own and know. Bu=
ilding solutions off of heavy weight tools like CLANG or a big lexer or wha=
tever may open up big long term opportunities and eventually minimize the a=
mount of =93boilerplate=94 someone needs to write, but it requires you (and=
anyone who will extend or maintain the system) to develop deep knowledge o=
f some seriously complex software, so much so that it may make the investme=
nt prohibitive.<u></u><u></u></span></p>
<p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca=
libri","sans-serif";color:#1f497d"><u></u>=A0<u></u></span><=
/p><p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"=
;Calibri","sans-serif";color:#1f497d">-Nathan<u></u><u></u><=
/span></p>
<p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca=
libri","sans-serif";color:#1f497d"><u></u>=A0<u></u></span><=
/p><div><div style=3D"border:none;border-top:solid #b5c4df 1.0pt;padding:3.=
0pt 0in 0in 0in">
<p class=3D"MsoNormal"><b><span style=3D"font-size:10.0pt;font-family:"=
;Tahoma","sans-serif"">From:</span></b><span style=3D"font-s=
ize:10.0pt;font-family:"Tahoma","sans-serif""> <a href=
=3D"mailto:[email protected]" target=3D"_blank"=
>[email protected]</a> [mailto:<a href=3D"mailt=
o:[email protected]" target=3D"_blank">sweng-ga=
[email protected]</a>] <b>On Behalf Of </b>Adrian Stone=
<br>
<b>Sent:</b> Thursday, March 14, 2013 4:29 PM<br><b>To:</b> <a href=3D"mail=
to:[email protected]" target=3D"_blank">sweng-gamedev@midnigh=
tryder.com</a><br><b>Subject:</b> Re: [Sweng-Gamedev] Reflection in game en=
gine (c++)<u></u><u></u></span></p>
</div></div><p class=3D"MsoNormal"><u></u>=A0<u></u></p><p class=3D"MsoNorm=
al"><span style=3D"font-size:10.0pt;font-family:"Arial","san=
s-serif";color:navy"><u></u>=A0<u></u></span></p><p class=3D"MsoNormal=
"><span style=3D"font-size:10.0pt;font-family:"Arial","sans-=
serif";color:navy">I=92m not sure which number describes our approach,=
but we=92ve been using it for about 8 years on many different projects and=
I believe everyone on the team has been very happy with it.=A0 I=92ve writ=
ten about it pretty extensively here: <a href=3D"http://gameangst.com/?p=3D=
107" target=3D"_blank">http://gameangst.com/?p=3D107</a><u></u><u></u></spa=
n></p>
<p class=3D"MsoNormal"><span style=3D"font-size:10.0pt;font-family:"Ar=
ial","sans-serif";color:navy"><u></u>=A0<u></u></span></p><p=
class=3D"MsoNormal"><span style=3D"font-size:10.0pt;font-family:"Aria=
l","sans-serif";color:navy">There are some implementation de=
tails I=92d change if I were starting over from scratch, but I still think =
that using advanced C++ features to create an embedded DSL is the best opti=
on for reflection in C++.<u></u><u></u></span></p>
<p class=3D"MsoNormal"><span style=3D"font-size:10.0pt;font-family:"Ar=
ial","sans-serif";color:navy"><u></u>=A0<u></u></span></p><p=
class=3D"MsoNormal"><span style=3D"font-size:10.0pt;font-family:"Aria=
l","sans-serif";color:navy">Adrian<u></u><u></u></span></p>
<p class=3D"MsoNormal"><span style=3D"font-size:10.0pt;font-family:"Ar=
ial","sans-serif";color:navy"><u></u>=A0<u></u></span></p><p=
class=3D"MsoNormal"><span style=3D"font-size:10.0pt;font-family:"Aria=
l","sans-serif";color:navy"><u></u>=A0<u></u></span></p>
<div style=3D"border:none;border-left:solid blue 1.5pt;padding:0in 0in 0in =
4.0pt"><div><div class=3D"MsoNormal" align=3D"center" style=3D"text-align:c=
enter"><hr size=3D"2" width=3D"100%" align=3D"center"></div><p class=3D"Mso=
Normal"><b><span style=3D"font-size:10.0pt;font-family:"Tahoma",&=
quot;sans-serif"">From:</span></b><span style=3D"font-size:10.0pt;font=
-family:"Tahoma","sans-serif""> <a href=3D"mailto:sweng=
[email protected]" target=3D"_blank">sweng-gamedev-b=
[email protected]</a> [<a href=3D"mailto:sweng-gamedev-bounces=
@lists.midnightryder.com" target=3D"_blank">mailto:sweng-gamedev-bounces@li=
sts.midnightryder.com</a>] <b>On Behalf Of </b>Alen Ladavac<br>
<b>Sent:</b> Thursday, March 14, 2013 6:45 PM<br><b>To:</b> Gabriel Sassone=
<br><b>Cc:</b> <a href=3D"mailto:[email protected]" tar=
get=3D"_blank">[email protected]</a>; <a href=3D"mailto=
:[email protected]" target=3D"_blank">sweng-gamedev@midnightr=
yder.com</a><br>
<b>Subject:</b> Re: [Sweng-Gamedev] Reflection in game engine (c++)</span><=
u></u><u></u></p></div><p class=3D"MsoNormal"><u></u>=A0<u></u></p><p class=
=3D"MsoNormal" style=3D"margin-bottom:12.0pt"><span style=3D"font-size:9.0p=
t;font-family:"Courier New"">We've been using #4 in our proje=
cts for a decade already and it works a treat. And... why couldn't you =
invoke methods? :)<br>
<br>That method is the only really fully portable (AFAIK), as it doesn'=
t really care what compiler/toolset you have. It is also very light in term=
s of runtime requirements, and very easy to use (not much extra typing for =
each class, member or function).=A0<br>
<br>Though it is rather involved to implement.<br><br>JM2C,<br>Alen<br><br>=
Thursday, March 14, 2013, 7:09:30 PM, you wrote:</span><u></u><u></u></p><t=
able border=3D"0" cellpadding=3D"0"><tbody><tr><td width=3D"15" style=3D"wi=
dth:11.25pt;background:blue;padding:.75pt .75pt .75pt .75pt">
<p class=3D"MsoNormal"><u></u>=A0<u></u></p></td><td width=3D"1142" style=
=3D"width:856.5pt;padding:.75pt .75pt .75pt .75pt"><p class=3D"MsoNormal"><=
span style=3D"font-size:9.0pt;font-family:"Courier New"">Hello ge=
nts,<br>=A0 =A0I wanted to experiment with reflection and I found different=
way to obtain it:<br>
<br>=A0 1) Invasive macro based registration<br>=A0 2) Reflection visitor p=
attern<br>=A0 3) Parsing pdb/clang stuff and create a manual table of what =
you want/need<br>=A0 4) c++ custom parser that uses tags to create reflecti=
on informations (like a comment near a member, ...) (exuberant ctags???)<br=
>
=A0 5) create serializable/reflected classes in a data format, then run a t=
ool that generates headers and cpps<br><br>I am trying to figure out flaws =
and merits of each kind, and even if there are other solutions.<br>I love t=
he idea to have the possibility to serialize in and out structures, access =
fields and change values, stream in/out stuff from network ,and maybe link =
with scripting.<br>
<br>My goal is to have fast iteration times, both artists and programmers, =
and I achieved it for rendering programmers already with having json binari=
zed configurable rendering, but still there are code stuff that are not eas=
y to achieve.<br>
<br>Here are my thoughts, but I would like to hear your ideas and experienc=
es!<br><br>1) Very precise on what you can register/serialize, but painful =
to maintain or plug into an existing codebase<br>2) Less precise but you ju=
st need one method per class, that you can use to serialize/reflect. Still =
bad in maintaining, but better in plugging in.<br>
3) You make the compiler do the work, then translate the informations you n=
eed in your format. Easy to maintain, to plug...maybe slow in parsing? Slow=
your build pipeline?<br>4) maybe easier than using pdbs, but less powerful=
(you cannot invoke methods on objects). should be faster than 3.<br>
5) crazy idea. requires generation of code from outside...powerful like 4, =
so data reflection, but you cannot invoke methods if you want.<br><br>What =
are your experiences/thoughts?<br><br>Thanks to everyone that read this mai=
l!<br>
=A0<br>=A0 =A0 Gabriel</span><span class=3D"HOEnZb"><font color=3D"#888888"=
><u></u><u></u></font></span></p></td></tr></tbody></table><span class=3D"H=
OEnZb"><font color=3D"#888888"><p class=3D"MsoNormal"><br><br><br><br><i><s=
pan style=3D"font-family:"Arial","sans-serif";color:sil=
ver">--=A0<br>
Best regards,<br>=A0Alen =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0</span></i><a href=3D"mailto:[email protected]" target=3D"_blank"=
>mailto:[email protected]</a><u></u><u></u></p></font></span></div></div=
></div><br>_______________________________________________<br>
Sweng-Gamedev mailing list<br>
<a href=3D"mailto:[email protected]">Sweng-Gamedev@list=
s.midnightryder.com</a><br>
<a href=3D"http://lists.midnightryder.com/listinfo.cgi/sweng-gamedev-midnig=
htryder.com" target=3D"_blank">http://lists.midnightryder.com/listinfo.cgi/=
sweng-gamedev-midnightryder.com</a><br>
<br></blockquote></div><br></div>
--20cf30363f75dfba9204d7ebc5cd--
--===============0473400601==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
_______________________________________________
Sweng-Gamedev mailing list
[email protected]
http://lists.midnightryder.com/listinfo.cgi/sweng-gamedev-midnightryder.com
--===============0473400601==--