0

It there a way to control existence of data members in C++ template based on template arguments?

I have vec template which represents N-dimensional vector (like 2D, 3D, 4D…). Here is the cut:

template <typename T, size_t dim>
struct vec {    
    union {
        T d[dim];
        struct {
            T x, y, z, w;
        };
    };
};

The idea is that I can access the fields like

vec<float,3> vec3;
vec.d[0]=0.0;
vec.d[1]=1.0;

with any number of dimensions and for "classical" first four dimensions with the notation above I can use well-known aliases x,y,z,w, like here:

vec.x = 0.0 

Here “x” is the alias for the d[0].

Having the direct access to the fields is key here, I don't want to have accessors notation; so methods to get access to d don't work for me.

The problem is that for vec<float,2> I don’t need z and w. Is there a way to use something (expect full template specialization) like std::conditional, std::enable_if to control existence of these members? I’d like to write in the template something like:

struct {
    T x, std::enable(dim>1,y), std::enable(dim>2,z), std::enable(dim>3,w);
};

It would be nice to avoid boost and other extra libraries. STL would work fine.

Is there any control for this?

Damir Tenishev
  • 1,275
  • 3
  • 14
  • In C++ this is called "template specialization". You will declare specific specializations for your template based on its `size_t` parameter (and likely leave the actual template completely undefined(!) leaving behind only its specializations). This is a highly advanced, and one of the most complicated fundamental aspects of C++ that cannot be adequately explained in just one or two sentences on Stackoverflow. See your C++ textbook for a complete explanation and examples. – Sam Varshavchik Feb 28 '21 at 19:40
  • Hi @SamVarshavchik, I am well aware of the template specializations. I have long experience with C++. Please see my initial question carefully. Here is the quote: "Is there a way to use something (expect full template specialization)". I don't want to have specializations since they are risky here. I am quite sure that C++ should have a way to do this inside the template. That's what I am looking for. And the https://stackoverflow.com/questions/61678718/declaring-an-optional-class-field-using-templates-in-c doesn't work for me, since I want to have a condition based on a number, not type. – Damir Tenishev Feb 28 '21 at 19:49
  • No, there is no way to do that in C++, other than specializing the template. `std::conditional`, `std::enable_if_t` cannot be used to declare class members, C++ does not work this way. I am not sure what's so "risky" about specializations. There's nothing more "risky" about them than anything else in C++. – Sam Varshavchik Feb 28 '21 at 20:02
  • Can we chat on this site somehow? Now I am trying: template struct v { }; template struct v { T x; }; template struct v { T x, y; }; template struct v { T x, y, z; }; but it doesn't work for me in the vec template: template struct vec { union { T d[dim]; struct : public v {}; }; Looking for a workaround. I don't want to specialize the whole template vec. It is risky sine will have code duplication. Can you help with clues? – Damir Tenishev Feb 28 '21 at 20:22
  • @SamVarshavchik Precisely, I am stuck at why template struct vec { union { T d[dim]; struct { T x, y, z; }; }; }; works just fine and (simplified for this example) struct v2 { float x, y; }; template struct vec { union { T d[dim]; struct : v2 {}; }; }; doesn't. That's what makes my specialization which I use instead of v2 doesn't work. Any clue? – Damir Tenishev Feb 28 '21 at 20:40
  • This piece is pretty close to the https://stackoverflow.com/questions/34075606/using-inheritance-within-a-union Any suggestions how this could be solved even with specializations but avoiding to override all vec template> – Damir Tenishev Feb 28 '21 at 20:52
  • Unions are fragile. Better to not mess with it and specialise vec itself. You can further inherit from it for any common stuff. – rustyx Feb 28 '21 at 21:08
  • @rustyx, the question is how to make this aliasing without duplicating the code for every dimension like 1,2,3,4 while making the specializations? Is there a change to make a partial specialization for this (aliasing) part only? – Damir Tenishev Feb 28 '21 at 21:16
  • Well, I finally implemented this with the partial specializations. I don't like the solution, so I will publish it soon separately and ask for better ideas. – Damir Tenishev Feb 28 '21 at 21:26

0 Answers0