C++ Method Type Deduction Tricks

Working on the next part of the C++ Metadata series, I decided that I didn't like the way I was handling setters and getters for object properties. I wanted something even faster and with even less overhead while retaining the extreme simplicity of my API. I discovered some tricks (only tested in Visual Studio 2010 so far) that do exactly what I need. I'm afraid I'm a little too swamped to write anything about how these tricks work just now, but I wanted to get the code out there.

I may update the article with explanations of what's going on and why this all works later if time permits.


// debugging macro

define assert(expr) do{ if (!(expr)) __debugbreak(); }while(0)

// getter/setter typedefs typedef void(Getter)(const void object, void* out_value);
typedef void(Setter)(void object, const void* value);

// deduce if a getter is const or not template
std::truetype deduceconstness(ReturnType(ObjectType::*getter)() const);

std::falsetype deduceconstness(ReturnType(ObjectType::*getter)());

// deduce the object type of a getter/setter pointer-to-method template
ObjectType deduce_object(ReturnType(ObjectType::*getter)() const);

ObjectType deduce_object(ReturnType(ObjectType::*getter)());

ObjectType deduce_object(ReturnType(ObjectType::*getter)(SetType));

// deduce the return type of a getter/setter pointer-to-method template
ReturnType deducereturnval(ReturnType(ObjectType::*getter)() const);

ReturnType deducereturnval(ReturnType(ObjectType::*getter)());

ReturnType deducereturnval(ReturnType(ObjectType::*getter)(SetType));

// deduce the parameter type of a setter pointer-to-method template
SetType deducefirstparam(ReturnType(ObjectType::*setter)(SetType value));

// wrapper for a const getter template
struct wrapgetter
{ template static void thunk(const void* object, void* out
value) { const ObjectType* typedobject = reinterpretcast(object); ReturnType* typedvalue = reinterpretcast(outvalue); *typedvalue = (typed_object->*Getter)(); } };

// wrapper for a non-const getter template
struct wrapgetter
{ template static void thunk(const void* object, void* out
value) { ObjectType* typedobject = reinterpretcast(constcast(object)); ReturnType* typedvalue = reinterpretcast(outvalue); typed_value = (typed_object->Getter)(); } };

// wrapper for a setter template
struct wrapsetter
{ template static void thunk(void* object, const void* value) { ObjectType* typed
object = reinterpretcast(object); const SetType* typedvalue = reinterpretcast(value); (typedobject->Setter)(typed_value); } };

// construction macros

define GETTER(method) \

(&wrapgetter::value, decltype(deduceobject(method)), decltype(deducereturnval(method))>::thunk)

define SETTER(method) \


// test object class TestObject
{ public:
TestObject(): i(5), f(2.f) {}

int getInt() const { return i; } float getFloat() { return f; }

void setInt(int i) { i = i; } float setFloat(float f) { return f = f; }

int i; float f; };

// test code int main()
{ Getter calli = GETTER(&TestObject::getInt); Getter callf = GETTER(&TestObject::getFloat);

Setter seti = SETTER(&TestObject::setInt); Setter setf = SETTER(&TestObject::setFloat);

TestObject o; int i; float f;

calli(&o, &i); callf(&o, &f);

assert(i o.i); assert(f o.f);

i = 10; f = 7.f;

seti(&o, &i); setf(&o, &f);

assert(o.i i); assert(o.f f); }