-
Notifications
You must be signed in to change notification settings - Fork 73
ReflectionInCpp
#Reflection in C++
Some kind of reflection functionality is pretty useful to have for tools...
Imagine we have a POD native type containing properties and settings:
class ModelVisSettings
{
public:
std::string _modelName;
RenderCore::Techniques::CameraDesc _camera;
};
We want to automatically bind this object to a properties dialog in such a way that a user can change settings.
##Different types of reflection
There's a great thread on StackOverflow discussing some different possibilites. http://stackoverflow.com/questions/41453/how-can-i-add-reflection-to-a-c-application
Let's look at different options.
###Create a C++/CLI wrapper
A simple method would be to just create a wrapper class in C++/CLI with the same members. We can use the CLI annotations to add extra data to fields (such as what editor to use, etc). But we have to maintain 2 separate classes.
It's simple, it's fairly practical... But it's a little extra work.
###Build reflection data with external compiler
There seem to be a few tools that can parser C++ code and build a database of type information. That type information can be read during runtime.
This looks like a good tool:
This requires an extra compile step, and might impose restrictions on build tool optiosn.
###Reflection field data outside of the class
Using a system of macros and templates, we can manually add type data with C++. Here's an example: http://www.axelmenzel.de/projects/coding/rttr
RTTR_REFLECT
{
class_<Mesh>()
.constructor<>()
.constructor<const std::string&>()
.enumeration<E_TransformSpace>({{"TS_LOCAL", TS_LOCAL},
{"TS_PARENT", TS_PARENT},
{"TS_WORLD", TS_WORLD}})
.property("pos", &Mesh::getPosition, &Mesh::setPosition)
.method("setDirection", &Mesh::setDirection);
}
This creates a new class that contains static information describing the layout of another class.
###Reflection field data within a class
This is a common solution... We can implement some macros that add a table of reflection data with a class.
That StackOverflow page contains a pretty interesting implementing using variadic macros:
These macros separate the type name from the variable name, in a pretty neat and clean why:
#define REM(...) __VA_ARGS__
#define EAT(...)
// Retrieve the type
#define TYPEOF(x) DETAIL_TYPEOF(DETAIL_TYPEOF_PROBE x,)
#define DETAIL_TYPEOF(...) DETAIL_TYPEOF_HEAD(__VA_ARGS__)
#define DETAIL_TYPEOF_HEAD(x, ...) REM x
#define DETAIL_TYPEOF_PROBE(...) (__VA_ARGS__),
// Strip off the type
#define STRIP(x) EAT x
// Show the type without parenthesis
#define PAIR(x) REM x
This particular implementation looks pretty clean. But this style of implementation tends to involve more complex macros than reflection data outside of the class.
With this method, we need to change the actual implementation of the class we want to reflect. This means we can't add reflection data to classes in third party libraries.
###Using DLL export hacks
We can get some type information from the DLL exports table using __declspec(dllexport)
.
This would only give us methods (not members). By perhaps we can combine it with __declspec(property)
?
It also means we have to fill up our dllexports table with information -- that could possibly be unsecure?
##So many options
So many options... The system of macros on the StackOverflow page looks really interesting.
But it may be that just creating a C++/CLI wrapper is just more practical in the long-run. Plus, the wrapper allows us to add annotation data (or make any other transformations to the data as it passes through the UI).
If we need reflection data for purposes other than binding to the UI, then perhaps a good built-in reflection solution would make sense.
Or if we really wanted to be able to bind arbitrary C++ types of the UI, we could do that with reflection. But I wonder how useful that would really be.