Gamasutra is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Gamasutra: The Art & Business of Making Gamesspacer
Sponsored Feature: Behind the Mirror - Adding Reflection to C++
arrowPress Releases
May 24, 2019
Games Press
View All     RSS








If you enjoy reading this site, you might also want to check out these UBM Tech sites:


 

Sponsored Feature: Behind the Mirror - Adding Reflection to C++


May 17, 2011 Article Start Previous Page 3 of 3
 

Populating the Data Model

To help populate the data model, some template functions can help extract useful data via template parameters (see Listing 3).

A template function with parameters for the object type and variable type provides an easy way to extract the size of the variable and its offset from the base instance pointer (using a pointer to member variable), while also supporting the use of template specialization to deduce which type of data object is applicable to this field. Three important things are happening in this function to extract data for our reflection data model: pointer to member variable C++ syntax, translation of this syntax into an offset from a base object address, and the use of deduction using explicit specialization.

Pointer to Member Variables

Pointer to member variables are a pretty infrequently used aspect of C++. It does what you might expect, but its syntax is strange if you haven't seen it before:

int32_t Object::* pointer_to_member_variable = &Object::m_Member;
// These are typically dereferenced with an instance of the object
// type (just like member function pointers):
Object object, *pointer = new Object;
int32_t value1 = object.*pointer_to_member_variable;
int32_t value2 = pointer->*pointer_to_member_variable;

// To compute the offset from a pointer to a member variable
template< class ObjectT, class DataT >
uint32_t GetFieldOffset( ObjectT DataT::* field )
{
// a pointer-to-member is really just an offset value
// disguised by the compiler
return (uint32_t) (uintptr_t) &( ((ObjectT*)NULL)->*field );
}

This function doesn't bother with allocating an instance to dereference the pointer to member variable. It substitutes a NULL pointer, deferences the pointer to member variable, and uses the address operator to yield the offset (from NULL) at which the pointed member exists. Some of this syntax may seem strange, but it's a perfect fit for maximizing what information is needed to describe a field in a single function parameter.

Explicit Specialization

DeduceDataClass is a good example of template deduction using explicit template specialization. This deduction technique is a way of using the C++ template mechanism to allow for the automatic selection of some information by the template compiler based only on a template parameter. The default template function's implementation returns NULL, indicating that the deduction failed since no specialization was found to find the associated data, as below:

template< class DataT >
Class* DeduceDataClass()
{
// unknown data!
return NULL;
}
// Then create an explicit specialization for every type that can
// be deduced:
template<>
Class* DeduceDataClass<uint32_t>()
{
// this specialization associates the uint32_t built in
// type with an object class that can
// process data of type uint32_t with respect to other
// persistence / cloning / mining code
return SimpleData< uint32_t >::s_Class;
}

In this case, a pointer is returned to the class reflection information for the type of data object to be used when dealing with the built-in type passed into the template argument. One more template will help keep the code that registers classes at startup concise, as seen in Listing 4.

Conclusion

Reflection can imbue an enormous amount of flexibility to your game engine, but this flexibility doesn't come without cost. However, the extra memory reflection data consumes is balanced by the time saved implementing features more rapidly. The ability to deliver changes to your users quickly, and with minimal engineering overhead, will pay dividends as your user base grows and your production time stretches across multiple titles.

Resources

Helium is an open source game engine toolkit that contains an implementation of C++ Reflection. Much of the code in this article was derived from it. It uses a BSD-style license, and is available at www.heliumproject.org. The reflection system itself is located in the Foundation/Reflect folder within the source repository.


Article Start Previous Page 3 of 3

Related Jobs

Pixar Animation Studios
Pixar Animation Studios — Emeryville, California, United States
[05.24.19]

Animation Tools Software Engineer
Disbelief
Disbelief — Chicago, Illinois, United States
[05.24.19]

Senior Programmer, Chicago
Disbelief
Disbelief — Chicago, Illinois, United States
[05.24.19]

Junior Programmer, Chicago
Deep Silver Volition
Deep Silver Volition — Champaign, Illinois, United States
[05.24.19]

Senior Animation Programmer





Loading Comments

loader image