Reputation: 391
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
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
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