Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Any way of adding member variable for specific template value?

Tags:

c++

templates

I have this math vector struct:

template <size_t _Size, typename _NumType>
struct Vector {
    _NumType elements[_Size];

    //... Other stuff ...
};

And I want to add variables depending on how many elements the vector has. Something like this:

_NumType& x = elements[0]; // Only if _Size >= 1
_NumType& y = elements[1]; // Only if _Size >= 2
_NumType& z = elements[2]; // Only if _Size >= 3

Making a base class/struct and then extending would be a solution but due to other code I can't do that (it would only make more problems).

Another solution I found is doing something I believe is called partial template specialization:

template <typename _NumType>
struct Vector<2U, _NumType> {
    _NumType& x = elements[0];
    _NumType& y = elements[1];

    //... Other stuff ...
};

The problem with this solution is that I would have to copy "other stuff" for each specialization which is something I'd rather avoid ("other stuff" is around 70 lines of code).

In case there is no solution I can elaborate on the problem with extending a base class but I hope it won't be necessary.

like image 831
MTNS Avatar asked Dec 14 '22 10:12

MTNS


1 Answers

partial template specialization can do the job, and to avoid code duplication you have to split the class, something like

template <size_t Size, typename T>
struct VectorData {
    T elements[Size];
};

template <typename T>
struct VectorData<2, T> {
    T elements[2];
    T& x = elements[0];
    T& y = elements[1];
};

template <typename T>
struct VectorData<3, T> {
    T elements[3];
    T& x = elements[0];
    T& y = elements[1];
    T& z = elements[2];
};

template <size_t Size, typename T>
struct Vector : VectorData<Size, T> {
    //... Other stuff ...
};

If you change reference to function, you might use SFINAE and since C++20, you might even discard some methods:

template <size_t Size, typename T>
struct Vector : VectorData<Size, T> {
    T elements[Size];

    T& x() requires (size == 2 || size == 3) { return elements[0]; }
    T& y() requires (size == 2 || size == 3) { return elements[0]; }
    T& z() requires (size == 3) { return elements[0]; }
    //... Other stuff ...
};
like image 123
Jarod42 Avatar answered Jan 11 '23 23:01

Jarod42