Alxe
Alxe

Reputation: 391

Providing aliases to Parent class data array in C++

Probably not the wisest choice, but modelling a Vertex<T, N> class to abstract Vertex2<T>, Vertex3<T> and Vertex4<T> implementations, providing basic access. It's structured like this:

template<typename T, unsigned N>
class _Vertex {
    const unsigned _size = N;
    T _data[N];

public:
    inline _Vertex() : _data() {};

    inline T const& operator[](int pos) const { return _data[pos]; } 
    inline T      & operator[](int pos)       { return _data[pos]; }
};

Say I want to implement Vertex2<T> as a Vertex<T, 2>, and provide aliases like x and y. The most proper way would be adding functions like:

 inline T const& x() const { return (*this)[0]; }
 inline T      & x()       { return (*this)[0]; }

This would be repeated for every property, or alias I'd like to add. It's not a bad design, but usage proves tricky as, provided v is of type Vector2<float>, v.x() = 1.0f is not as friendly as v.x = 1.0f.

Is there any way to provide clearer, friendlier alias?

My main thoughts were "abusing" memory layout, providing access to _data[i] accordingly, but I have no idea where to start.

This question is based on my "re-imagination" of a vertex.h header file provided for an assigment, so this makes it related to homework, but I can assure you the end is not. It's just my curiosity holding me off doing my homework!

Upvotes: 0

Views: 70

Answers (2)

Barry
Barry

Reputation: 303216

I put on my robe and Yakk hat.

operator->* is clearly underutilized in C++. We can overload to take a tag type of our choosing in a way that kind of looks like member access. Here's a simplified example:

template <size_t I> struct index_t { };
constexpr index_t<0> x{};
constexpr index_t<1> y{};

struct Vector {
    int data[2];

    template <size_t I>        
    int& operator->*(index_t<I> ) { return data[I]; }

    int& operator[](size_t idx) { return data[idx]; }
};

With that, we can do:

int main()
{
    Vector v{1, 2};
    std::cout << v.data[0] << ' ' << v.data[1] << '\n'; // 1 2
    v->*x = 42;
    v->*y = 17;
    std::cout << v.data[0] << ' ' << v.data[1] << '\n'; // 42 17
}

That said, don't do this. C++ doesn't have properties. The right way to do this would just be named functions that return lvalue references:

int& x();
int& y();

It may not be as "nice" as v.x but it gets the job done without having to add extra members to your class.

Upvotes: 1

Justin Finnerty
Justin Finnerty

Reputation: 329

v.x = 2.f is not the OOP/C++ way of member access. You are best off using get/set function like t = v.x() and v.x( t ).

It is possible to defeat the data encapsulation using the following:

template< class T >
class Vertex2 : private Vertex< T, 2 >
{
public:
   T & x;
   T & y;
   Vertex2(): Vertex< T, 2 >(), x((*this)[0]), y((*this)[1]) {}
};

This doesn't provide a const access but if you want to do v.x = you probably don't care too much about such things. Unfortunately, you are probably stuck with the extra memory of the two references.

Upvotes: 0

Related Questions