views:

287

answers:

2

What are the various options to implement a pointer-to-member construct in C++/CLI?

I have implemented some 2D geometry algorithms which perform some actions based on X and Y co-ordinates. I find that I am frequently duplicating code once for the X-axis and once for the Y-axis. An example is finding the maximum and minimum bounds along each axis.

Had I been using native C++, I could have used a pointer to the X or Y member (also width, height and so on) and passed it in as a parameter so that I need implement each algorithm only once. But with C++/CLI, this is not possible. What are my options? I am looking for something efficient, light-weight and terse.

+1  A: 

Option 1: if X and Y are exposed as public members, you could define them as part of an anonymous union, e.g:

class Shape {
public:
    union {
        struct { double X; double Y; };
        double point[2];
    };
    ...
};

This lets you access X as either shape.X or shape.point[0], and similarly, shape.Y as shape.point[1].

Option 2: If X and Y are exposed as properties, you could have their getters/setters access a member array of two elements, and then expose the array as a read-only property too. While the caller can't modify the array property, it can still modify its elements.

Option 3: well, not an option, really. Don't use .NET reflection to access the properties by name. The runtime cost is way too high.

Oren Trutner
+1  A: 

I'd make the argument a template type argument instead, and use functors that encapsulate property access. E.g.:

ref class Point {
     property int X;
     property int Y;
};

struct Point_X_accessor
{
     static int get(Point^ p) { return p->X; }
     static int set(Point^ p, int value) { p->X = value; }
};

struct Point_Y_accessor
{
     static int get(Point^ p) { return p->Y; }
     static int set(Point^ p, int value) { p->Y = value; }
};

template <class PointAccessor>
int some_algorithm(Point^ p) { ... }

some_algorithm<Point_X_accessor>(p);
some_algorithm<Point_Y_accessor>(p);

Of course, this only makes sense if you have sufficiently many sufficiently lengthy algorithms to justify all the boilerplate. Though the wrappers could be both generated and referenced via a macro, cutting down on lines of code quite a bit.

Pavel Minaev