convenient Vector3f classDo the C++ standards guarantee that unused private fields will influence sizeof?Is it a missed optimization, when a compile-time known reference takes space in a non-aggregate struct?When should you use a class vs a struct in C++?How to call a parent class function from derived class function?Meaning of 'const' last in a function declaration of a class?Memory comparison, which is faster?Failed to specialize function templateHow to sort “vector” which contains class objects? And why I am wrong?Accessing a static member function from another classFailure while trying to construct a std::list with an allocatorInconsistent overload resolution for constexpr member functions across compilers

SQL Always On COPY ONLY backups - what's the point if I cant restore the AG from these backups?

Can taking my 1-week-old on a 6-7 hours journey in the car lead to medical complications?

Project Euler Problem 45

Is Sanskrit really the mother of all languages?

How to create large inductors (1H) for audio use?

Phrase request for "work in" in the context of gyms

What's in a druid's grove?

Why would one hemisphere of a planet be very mountainous while the other is flat?

Book where main character comes out of stasis bubble

Entering the US with dual citizenship but US passport is long expired?

In-universe, why does Doc Brown program the time machine to go to 1955?

Golfball Dimples on spaceships (and planes)?

How to calculate the power level of a Commander deck?

Infinitely many primes

How could a planet have one hemisphere way warmer than the other without the planet being tidally locked?

Looking for a big fantasy novel about scholarly monks that sort of worship math?

Are there mathematical concepts that exist in the fourth dimension, but not in the third dimension?

What exactly is Apple Cider

Supervisor wants me to support a diploma-thesis SW tool after I graduated

Global variables and information security

Male viewpoint in an erotic novel

Who's this voice acting performer?

Why are some hotels asking you to book through Booking.com instead of matching the price at the front desk?

I won a car in a poker game. How is that taxed in Canada?



convenient Vector3f class


Do the C++ standards guarantee that unused private fields will influence sizeof?Is it a missed optimization, when a compile-time known reference takes space in a non-aggregate struct?When should you use a class vs a struct in C++?How to call a parent class function from derived class function?Meaning of 'const' last in a function declaration of a class?Memory comparison, which is faster?Failed to specialize function templateHow to sort “vector” which contains class objects? And why I am wrong?Accessing a static member function from another classFailure while trying to construct a std::list with an allocatorInconsistent overload resolution for constexpr member functions across compilers






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








6















Sometimes there is a need to have a Vector3f class, which has x, y and z members, and can be indexed as a float[3] array at the same time (there are several questions here at SO already about this).



Something like:



struct Vector3f 
float data[3];
float &x = data[0];
float &y = data[1];
float &z = data[2];
;


With this, we can write this:



Vector3f v;
v.x = 2.0f;
v.y = 3.0f;
v.z = 4.0f;
glVertex3fv(v.data);


But this implementation is bad, because references take space in the struct (which is quite unfortunate. I don't see any reason why references cannot be removed in this particular case, maybe it is missed optimization from the compiler's part).



But, with [[no_unique_address]] I had this idea:



#include <new>

template <int INDEX>
class Vector3fProperty
public:
operator float() const
return propertyValue();

float &operator=(float value)
float &v = propertyValue();
v = value;
return v;

private:
float &propertyValue()
return std::launder(reinterpret_cast<float*>(this))[INDEX];

float propertyValue() const
return std::launder(reinterpret_cast<const float*>(this))[INDEX];

;

struct Vector3f
[[no_unique_address]]
Vector3fProperty<0> x;
[[no_unique_address]]
Vector3fProperty<1> y;
[[no_unique_address]]
Vector3fProperty<2> z;

float data[3];
;

static_assert(sizeof(Vector3f)==12);


So, basically, I have properties in the struct, which handles the access to x, y and z. These properties should not take space, as they are empty, and have the attribute of [[no_unique_address]]



What do you think about this approach? Does it have UB?




Note, this question is about a class, for which all these are possible:



Vector3f v;
v.x = 1;
float tmp = v.x;
float *c = v.<something>; // there, c points to a float[3] array









share|improve this question





















  • 2





    @JesperJuhl: and there are cases, where this matters a lot.

    – geza
    8 hours ago






  • 4





    why not have v.data[0], v.data[1], v.data[2] and v.x(), v.y(), v.z()?

    – slepic
    8 hours ago






  • 1





    @JesperJuhl Unhelpful comment is unhelpful. Just because there may be specific applications where tripling the size of your type doesn't matter doesn't mean you shouldn't care at all about the implementation of fundamental library components like this.

    – Barry
    8 hours ago






  • 1





    @slepic: because that's a function call. v.x()=2.0f looks ugly. v.setX(2.0f) is not as terse as it could be.

    – geza
    8 hours ago






  • 4





    In this case, @JesperJuhl, I would personally assume it matters, on the grounds that "array of three floats and not doubles, specifically named x, y, and z" is highly suggestive of 3D graphics. It's thus likely to be used in a context where a large number of Vector3fs must be stored (to represent an object's vertices) and performance is extremely important (because it has to compete with other 3D graphics libraries), and thus essentially storing three pointers would be highly undesirable.

    – Justin Time
    7 hours ago

















6















Sometimes there is a need to have a Vector3f class, which has x, y and z members, and can be indexed as a float[3] array at the same time (there are several questions here at SO already about this).



Something like:



struct Vector3f 
float data[3];
float &x = data[0];
float &y = data[1];
float &z = data[2];
;


With this, we can write this:



Vector3f v;
v.x = 2.0f;
v.y = 3.0f;
v.z = 4.0f;
glVertex3fv(v.data);


But this implementation is bad, because references take space in the struct (which is quite unfortunate. I don't see any reason why references cannot be removed in this particular case, maybe it is missed optimization from the compiler's part).



But, with [[no_unique_address]] I had this idea:



#include <new>

template <int INDEX>
class Vector3fProperty
public:
operator float() const
return propertyValue();

float &operator=(float value)
float &v = propertyValue();
v = value;
return v;

private:
float &propertyValue()
return std::launder(reinterpret_cast<float*>(this))[INDEX];

float propertyValue() const
return std::launder(reinterpret_cast<const float*>(this))[INDEX];

;

struct Vector3f
[[no_unique_address]]
Vector3fProperty<0> x;
[[no_unique_address]]
Vector3fProperty<1> y;
[[no_unique_address]]
Vector3fProperty<2> z;

float data[3];
;

static_assert(sizeof(Vector3f)==12);


So, basically, I have properties in the struct, which handles the access to x, y and z. These properties should not take space, as they are empty, and have the attribute of [[no_unique_address]]



What do you think about this approach? Does it have UB?




Note, this question is about a class, for which all these are possible:



Vector3f v;
v.x = 1;
float tmp = v.x;
float *c = v.<something>; // there, c points to a float[3] array









share|improve this question





















  • 2





    @JesperJuhl: and there are cases, where this matters a lot.

    – geza
    8 hours ago






  • 4





    why not have v.data[0], v.data[1], v.data[2] and v.x(), v.y(), v.z()?

    – slepic
    8 hours ago






  • 1





    @JesperJuhl Unhelpful comment is unhelpful. Just because there may be specific applications where tripling the size of your type doesn't matter doesn't mean you shouldn't care at all about the implementation of fundamental library components like this.

    – Barry
    8 hours ago






  • 1





    @slepic: because that's a function call. v.x()=2.0f looks ugly. v.setX(2.0f) is not as terse as it could be.

    – geza
    8 hours ago






  • 4





    In this case, @JesperJuhl, I would personally assume it matters, on the grounds that "array of three floats and not doubles, specifically named x, y, and z" is highly suggestive of 3D graphics. It's thus likely to be used in a context where a large number of Vector3fs must be stored (to represent an object's vertices) and performance is extremely important (because it has to compete with other 3D graphics libraries), and thus essentially storing three pointers would be highly undesirable.

    – Justin Time
    7 hours ago













6












6








6


2






Sometimes there is a need to have a Vector3f class, which has x, y and z members, and can be indexed as a float[3] array at the same time (there are several questions here at SO already about this).



Something like:



struct Vector3f 
float data[3];
float &x = data[0];
float &y = data[1];
float &z = data[2];
;


With this, we can write this:



Vector3f v;
v.x = 2.0f;
v.y = 3.0f;
v.z = 4.0f;
glVertex3fv(v.data);


But this implementation is bad, because references take space in the struct (which is quite unfortunate. I don't see any reason why references cannot be removed in this particular case, maybe it is missed optimization from the compiler's part).



But, with [[no_unique_address]] I had this idea:



#include <new>

template <int INDEX>
class Vector3fProperty
public:
operator float() const
return propertyValue();

float &operator=(float value)
float &v = propertyValue();
v = value;
return v;

private:
float &propertyValue()
return std::launder(reinterpret_cast<float*>(this))[INDEX];

float propertyValue() const
return std::launder(reinterpret_cast<const float*>(this))[INDEX];

;

struct Vector3f
[[no_unique_address]]
Vector3fProperty<0> x;
[[no_unique_address]]
Vector3fProperty<1> y;
[[no_unique_address]]
Vector3fProperty<2> z;

float data[3];
;

static_assert(sizeof(Vector3f)==12);


So, basically, I have properties in the struct, which handles the access to x, y and z. These properties should not take space, as they are empty, and have the attribute of [[no_unique_address]]



What do you think about this approach? Does it have UB?




Note, this question is about a class, for which all these are possible:



Vector3f v;
v.x = 1;
float tmp = v.x;
float *c = v.<something>; // there, c points to a float[3] array









share|improve this question
















Sometimes there is a need to have a Vector3f class, which has x, y and z members, and can be indexed as a float[3] array at the same time (there are several questions here at SO already about this).



Something like:



struct Vector3f 
float data[3];
float &x = data[0];
float &y = data[1];
float &z = data[2];
;


With this, we can write this:



Vector3f v;
v.x = 2.0f;
v.y = 3.0f;
v.z = 4.0f;
glVertex3fv(v.data);


But this implementation is bad, because references take space in the struct (which is quite unfortunate. I don't see any reason why references cannot be removed in this particular case, maybe it is missed optimization from the compiler's part).



But, with [[no_unique_address]] I had this idea:



#include <new>

template <int INDEX>
class Vector3fProperty
public:
operator float() const
return propertyValue();

float &operator=(float value)
float &v = propertyValue();
v = value;
return v;

private:
float &propertyValue()
return std::launder(reinterpret_cast<float*>(this))[INDEX];

float propertyValue() const
return std::launder(reinterpret_cast<const float*>(this))[INDEX];

;

struct Vector3f
[[no_unique_address]]
Vector3fProperty<0> x;
[[no_unique_address]]
Vector3fProperty<1> y;
[[no_unique_address]]
Vector3fProperty<2> z;

float data[3];
;

static_assert(sizeof(Vector3f)==12);


So, basically, I have properties in the struct, which handles the access to x, y and z. These properties should not take space, as they are empty, and have the attribute of [[no_unique_address]]



What do you think about this approach? Does it have UB?




Note, this question is about a class, for which all these are possible:



Vector3f v;
v.x = 1;
float tmp = v.x;
float *c = v.<something>; // there, c points to a float[3] array






c++ c++20






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 8 hours ago







geza

















asked 8 hours ago









gezageza

16.2k3 gold badges39 silver badges95 bronze badges




16.2k3 gold badges39 silver badges95 bronze badges










  • 2





    @JesperJuhl: and there are cases, where this matters a lot.

    – geza
    8 hours ago






  • 4





    why not have v.data[0], v.data[1], v.data[2] and v.x(), v.y(), v.z()?

    – slepic
    8 hours ago






  • 1





    @JesperJuhl Unhelpful comment is unhelpful. Just because there may be specific applications where tripling the size of your type doesn't matter doesn't mean you shouldn't care at all about the implementation of fundamental library components like this.

    – Barry
    8 hours ago






  • 1





    @slepic: because that's a function call. v.x()=2.0f looks ugly. v.setX(2.0f) is not as terse as it could be.

    – geza
    8 hours ago






  • 4





    In this case, @JesperJuhl, I would personally assume it matters, on the grounds that "array of three floats and not doubles, specifically named x, y, and z" is highly suggestive of 3D graphics. It's thus likely to be used in a context where a large number of Vector3fs must be stored (to represent an object's vertices) and performance is extremely important (because it has to compete with other 3D graphics libraries), and thus essentially storing three pointers would be highly undesirable.

    – Justin Time
    7 hours ago












  • 2





    @JesperJuhl: and there are cases, where this matters a lot.

    – geza
    8 hours ago






  • 4





    why not have v.data[0], v.data[1], v.data[2] and v.x(), v.y(), v.z()?

    – slepic
    8 hours ago






  • 1





    @JesperJuhl Unhelpful comment is unhelpful. Just because there may be specific applications where tripling the size of your type doesn't matter doesn't mean you shouldn't care at all about the implementation of fundamental library components like this.

    – Barry
    8 hours ago






  • 1





    @slepic: because that's a function call. v.x()=2.0f looks ugly. v.setX(2.0f) is not as terse as it could be.

    – geza
    8 hours ago






  • 4





    In this case, @JesperJuhl, I would personally assume it matters, on the grounds that "array of three floats and not doubles, specifically named x, y, and z" is highly suggestive of 3D graphics. It's thus likely to be used in a context where a large number of Vector3fs must be stored (to represent an object's vertices) and performance is extremely important (because it has to compete with other 3D graphics libraries), and thus essentially storing three pointers would be highly undesirable.

    – Justin Time
    7 hours ago







2




2





@JesperJuhl: and there are cases, where this matters a lot.

– geza
8 hours ago





@JesperJuhl: and there are cases, where this matters a lot.

– geza
8 hours ago




4




4





why not have v.data[0], v.data[1], v.data[2] and v.x(), v.y(), v.z()?

– slepic
8 hours ago





why not have v.data[0], v.data[1], v.data[2] and v.x(), v.y(), v.z()?

– slepic
8 hours ago




1




1





@JesperJuhl Unhelpful comment is unhelpful. Just because there may be specific applications where tripling the size of your type doesn't matter doesn't mean you shouldn't care at all about the implementation of fundamental library components like this.

– Barry
8 hours ago





@JesperJuhl Unhelpful comment is unhelpful. Just because there may be specific applications where tripling the size of your type doesn't matter doesn't mean you shouldn't care at all about the implementation of fundamental library components like this.

– Barry
8 hours ago




1




1





@slepic: because that's a function call. v.x()=2.0f looks ugly. v.setX(2.0f) is not as terse as it could be.

– geza
8 hours ago





@slepic: because that's a function call. v.x()=2.0f looks ugly. v.setX(2.0f) is not as terse as it could be.

– geza
8 hours ago




4




4





In this case, @JesperJuhl, I would personally assume it matters, on the grounds that "array of three floats and not doubles, specifically named x, y, and z" is highly suggestive of 3D graphics. It's thus likely to be used in a context where a large number of Vector3fs must be stored (to represent an object's vertices) and performance is extremely important (because it has to compete with other 3D graphics libraries), and thus essentially storing three pointers would be highly undesirable.

– Justin Time
7 hours ago





In this case, @JesperJuhl, I would personally assume it matters, on the grounds that "array of three floats and not doubles, specifically named x, y, and z" is highly suggestive of 3D graphics. It's thus likely to be used in a context where a large number of Vector3fs must be stored (to represent an object's vertices) and performance is extremely important (because it has to compete with other 3D graphics libraries), and thus essentially storing three pointers would be highly undesirable.

– Justin Time
7 hours ago












5 Answers
5






active

oldest

votes


















3

















But this implementation is bad, because references take space in the struct (which is quite unfortunate. I don't see any reason why references cannot be removed in this particular case, maybe it is missed optimization from the compiler's part).




This looks like a complicated issue. Standard-layout classes have to be compatible between each other. And so compilers are not allowed to eliminate any member, regardless of how they are defined. For non standard-layout? Who knows. For more info read this: Do the C++ standards guarantee that unused private fields will influence sizeof?



From my experience compilers never remove class members, even if they are "unused" (e.g. formally sizeof does use them).




Does it have UB?




I think this is UB. First of all [[no_unique_address]] only means that the member need not have a unique address, not that it must not have a unique address. Secondly it is not clear where your data member starts. Again, compilers are free to use or not paddings of previous [[no_unique_address]] class members. Meaning your accessors may access incorrect piece of memory.



Another problem is that you want to access "outer" memory from the "inner" class. AFAIK such thing is also UB in C++.




What do you think about this approach?




Assuming it is correct (which is not) I still don't like it. You want getters/setters but C++ does not support this feature. So instead of doing those weird, complicated constructs (imagine other people maintaining this code) how about simply do



struct Vector3f 
float data[3];
float x()
return data[0];

void x(float value)
data[0] = value;

...
;


You say this code is ugly. Maybe it is. But it is simple, easy to read and maintain. There's no UB, it does not depend on potential hacks with unions, and does exactly what you want, except for beauty requirement. :)






share|improve this answer



























  • You may be interested, I asked the "remove class member" part here: stackoverflow.com/questions/57811424/…

    – geza
    6 hours ago


















4
















If this is going to live in a header, and you have some confidence in your compiler's optimizing capabilities, you can probably stick to a plain-old operator[]() overload and expect the compiler to be smart enough to elide the call and return the element that you want. E.g.:



class Vec3f 
public:
float x;
float y;
float z;

float &operator[](int i)
if(i == 0)
return x;

if(i == 1)
return y;

if(i == 2)
return z;


;


I tossed this into Compiler Explorer (https://godbolt.org/z/0X4FPL), which showed clang optimizing the operator[] call away at -O2, and GCC at -O3. Less exciting than your approach, but simple and should work under most circumstances.






share|improve this answer




















  • 1





    Well, this will be optimized only when i is known at compile time, right? godbolt.org/z/evVGPZ

    – freakish
    7 hours ago












  • True! What you are getting in your example is definitely less efficient than the optimal. However, in most applications with a fixed-size array, I imagine it would be uncommon for there to be situations where a specific index cannot be known at compile time. Either an index will be supplied as a literal, or there will be loops over [0,2]. This is of course highly application sensitive, so the anonymous structs/unions proposed by @Xirema is probably the best way to go.

    – youngmit
    7 hours ago


















1
















GLM implements this kind of functionality using anonymous structs inside an anonymous union



I can't personally guarantee that this is standard-compliant, but most major compilers (MSVC, GCC, Clang) will support this idiom:



struct Vector3f 
union
struct
float x, y, z;
;
struct
float data[3];
;
;
Vector3f() : Vector3f(0,0,0)
Vector3f(float x, float y, float z) : x(x), y(y), z(z)
;

int main()
Vector3f vec;
vec.x = 14.5;
std::cout << vec.data[0] << std::endl; //Should print 14.5
vec.y = -22.345;
std::cout << vec.data[1] << std::endl; //Should print -22.345
std::cout << sizeof(vec) << std::endl; //On most platforms will print 12



The non-standard behavior is in the anonymous struct used to group the letters together, which GCC will issue a warning about. As far as I know, the union itself should be valid, because the datatypes are all identical, but you should still check with your compiler documentation if you're unsure whether this is valid or not.



As an added convenience, we can also overload the brackets operator to shorten our syntax a little:



struct Vector3f 
/*...*/
float& operator[](size_t index) return data[index];
float operator[](size_t index) const return data[index];
;



int main()
Vector3f vec;
vec.x = 14.5;
std::cout << vec[0] << std::endl; //Should print 14.5
vec.y = -22.345;
std::cout << vec[1] << std::endl; //Should print -22.345
std::cout << sizeof(vec) << std::endl; //On most platforms will print 12




Just for clarity, accessing inactive members in the way I am is valid according to the C++ standard, because those members share a "common subsequence":




If two union members are standard-layout types, it's well-defined to examine their common subsequence on any compiler.



CPP Reference: Union Declaration




Because x and data[0] are



  • Both floats,

  • Both occupy the same memory,

  • Are both standard Layout types as the standard defines them,

It's perfectly valid to access one or the other regardless of which is currently active.






share|improve this answer






















  • 1





    This is UB. C++ (unlike C) does not allow accessing other union members once initialized with one.

    – freakish
    8 hours ago







  • 1





    @freakish It does if (and only if) the types of the inactive union members are the same as the active members and occupy the same memory.

    – Xirema
    8 hours ago











  • @Xirema it is technically UB from a standards perspective. However AFAIK all compilers have chosen to define the behavior for compatibility reasons (within reason). Unless you're thinking that "compatible types" makes this OK...

    – Mgetz
    8 hours ago







  • 3





    it's UB and uses two GNU extensions a) anonymous struct not allowed by ISO . b) union type punning works. Not ALL compilers support that, but GNU collections works in non-strict mode. Xinera misquotes clause, because it relates to stucts with common begin, which isn't the case here.

    – Swift - Friday Pie
    8 hours ago







  • 3





    common sequence doesn't apply here.. it would have applied if both members were standard-layout ctypes with equivalent declarations. Either two arrays or two structs. SO it's technically type punning, because way how array is aligned may be (platform defined) different from struct.. especially if certain pragmas were used in code.

    – Swift - Friday Pie
    8 hours ago



















0
















As stated, this is impossible: pointer arithmetic is defined only within an array, and there’s no way (without putting a reference in the class, which takes up space in current implementations) to have v.x refer to an array element.






share|improve this answer
































    0
















    There's no need for reinterpret_cast, nor unions. You can define a simple operator[]:



    struct Vector3f 
    float x, y, z;
    float& operator[](std::size_t i)return *(&x + i);
    ;


    If you want a strong guarantee that this will work, though, you need to make sure that your class is Standard Layout. In practice, it should work in most cases, even if it's not. For instance, don't add any virtual functions to this class.






    share|improve this answer

























    • Pointer arithmetic cannot be used to move from one member to another, only within arrays.

      – Davis Herring
      3 hours ago













    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );














    draft saved

    draft discarded
















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f57810925%2fconvenient-vector3f-class%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    5 Answers
    5






    active

    oldest

    votes








    5 Answers
    5






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    3

















    But this implementation is bad, because references take space in the struct (which is quite unfortunate. I don't see any reason why references cannot be removed in this particular case, maybe it is missed optimization from the compiler's part).




    This looks like a complicated issue. Standard-layout classes have to be compatible between each other. And so compilers are not allowed to eliminate any member, regardless of how they are defined. For non standard-layout? Who knows. For more info read this: Do the C++ standards guarantee that unused private fields will influence sizeof?



    From my experience compilers never remove class members, even if they are "unused" (e.g. formally sizeof does use them).




    Does it have UB?




    I think this is UB. First of all [[no_unique_address]] only means that the member need not have a unique address, not that it must not have a unique address. Secondly it is not clear where your data member starts. Again, compilers are free to use or not paddings of previous [[no_unique_address]] class members. Meaning your accessors may access incorrect piece of memory.



    Another problem is that you want to access "outer" memory from the "inner" class. AFAIK such thing is also UB in C++.




    What do you think about this approach?




    Assuming it is correct (which is not) I still don't like it. You want getters/setters but C++ does not support this feature. So instead of doing those weird, complicated constructs (imagine other people maintaining this code) how about simply do



    struct Vector3f 
    float data[3];
    float x()
    return data[0];

    void x(float value)
    data[0] = value;

    ...
    ;


    You say this code is ugly. Maybe it is. But it is simple, easy to read and maintain. There's no UB, it does not depend on potential hacks with unions, and does exactly what you want, except for beauty requirement. :)






    share|improve this answer



























    • You may be interested, I asked the "remove class member" part here: stackoverflow.com/questions/57811424/…

      – geza
      6 hours ago















    3

















    But this implementation is bad, because references take space in the struct (which is quite unfortunate. I don't see any reason why references cannot be removed in this particular case, maybe it is missed optimization from the compiler's part).




    This looks like a complicated issue. Standard-layout classes have to be compatible between each other. And so compilers are not allowed to eliminate any member, regardless of how they are defined. For non standard-layout? Who knows. For more info read this: Do the C++ standards guarantee that unused private fields will influence sizeof?



    From my experience compilers never remove class members, even if they are "unused" (e.g. formally sizeof does use them).




    Does it have UB?




    I think this is UB. First of all [[no_unique_address]] only means that the member need not have a unique address, not that it must not have a unique address. Secondly it is not clear where your data member starts. Again, compilers are free to use or not paddings of previous [[no_unique_address]] class members. Meaning your accessors may access incorrect piece of memory.



    Another problem is that you want to access "outer" memory from the "inner" class. AFAIK such thing is also UB in C++.




    What do you think about this approach?




    Assuming it is correct (which is not) I still don't like it. You want getters/setters but C++ does not support this feature. So instead of doing those weird, complicated constructs (imagine other people maintaining this code) how about simply do



    struct Vector3f 
    float data[3];
    float x()
    return data[0];

    void x(float value)
    data[0] = value;

    ...
    ;


    You say this code is ugly. Maybe it is. But it is simple, easy to read and maintain. There's no UB, it does not depend on potential hacks with unions, and does exactly what you want, except for beauty requirement. :)






    share|improve this answer



























    • You may be interested, I asked the "remove class member" part here: stackoverflow.com/questions/57811424/…

      – geza
      6 hours ago













    3














    3










    3










    But this implementation is bad, because references take space in the struct (which is quite unfortunate. I don't see any reason why references cannot be removed in this particular case, maybe it is missed optimization from the compiler's part).




    This looks like a complicated issue. Standard-layout classes have to be compatible between each other. And so compilers are not allowed to eliminate any member, regardless of how they are defined. For non standard-layout? Who knows. For more info read this: Do the C++ standards guarantee that unused private fields will influence sizeof?



    From my experience compilers never remove class members, even if they are "unused" (e.g. formally sizeof does use them).




    Does it have UB?




    I think this is UB. First of all [[no_unique_address]] only means that the member need not have a unique address, not that it must not have a unique address. Secondly it is not clear where your data member starts. Again, compilers are free to use or not paddings of previous [[no_unique_address]] class members. Meaning your accessors may access incorrect piece of memory.



    Another problem is that you want to access "outer" memory from the "inner" class. AFAIK such thing is also UB in C++.




    What do you think about this approach?




    Assuming it is correct (which is not) I still don't like it. You want getters/setters but C++ does not support this feature. So instead of doing those weird, complicated constructs (imagine other people maintaining this code) how about simply do



    struct Vector3f 
    float data[3];
    float x()
    return data[0];

    void x(float value)
    data[0] = value;

    ...
    ;


    You say this code is ugly. Maybe it is. But it is simple, easy to read and maintain. There's no UB, it does not depend on potential hacks with unions, and does exactly what you want, except for beauty requirement. :)






    share|improve this answer
















    But this implementation is bad, because references take space in the struct (which is quite unfortunate. I don't see any reason why references cannot be removed in this particular case, maybe it is missed optimization from the compiler's part).




    This looks like a complicated issue. Standard-layout classes have to be compatible between each other. And so compilers are not allowed to eliminate any member, regardless of how they are defined. For non standard-layout? Who knows. For more info read this: Do the C++ standards guarantee that unused private fields will influence sizeof?



    From my experience compilers never remove class members, even if they are "unused" (e.g. formally sizeof does use them).




    Does it have UB?




    I think this is UB. First of all [[no_unique_address]] only means that the member need not have a unique address, not that it must not have a unique address. Secondly it is not clear where your data member starts. Again, compilers are free to use or not paddings of previous [[no_unique_address]] class members. Meaning your accessors may access incorrect piece of memory.



    Another problem is that you want to access "outer" memory from the "inner" class. AFAIK such thing is also UB in C++.




    What do you think about this approach?




    Assuming it is correct (which is not) I still don't like it. You want getters/setters but C++ does not support this feature. So instead of doing those weird, complicated constructs (imagine other people maintaining this code) how about simply do



    struct Vector3f 
    float data[3];
    float x()
    return data[0];

    void x(float value)
    data[0] = value;

    ...
    ;


    You say this code is ugly. Maybe it is. But it is simple, easy to read and maintain. There's no UB, it does not depend on potential hacks with unions, and does exactly what you want, except for beauty requirement. :)







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited 7 hours ago

























    answered 7 hours ago









    freakishfreakish

    41.6k7 gold badges102 silver badges142 bronze badges




    41.6k7 gold badges102 silver badges142 bronze badges















    • You may be interested, I asked the "remove class member" part here: stackoverflow.com/questions/57811424/…

      – geza
      6 hours ago

















    • You may be interested, I asked the "remove class member" part here: stackoverflow.com/questions/57811424/…

      – geza
      6 hours ago
















    You may be interested, I asked the "remove class member" part here: stackoverflow.com/questions/57811424/…

    – geza
    6 hours ago





    You may be interested, I asked the "remove class member" part here: stackoverflow.com/questions/57811424/…

    – geza
    6 hours ago













    4
















    If this is going to live in a header, and you have some confidence in your compiler's optimizing capabilities, you can probably stick to a plain-old operator[]() overload and expect the compiler to be smart enough to elide the call and return the element that you want. E.g.:



    class Vec3f 
    public:
    float x;
    float y;
    float z;

    float &operator[](int i)
    if(i == 0)
    return x;

    if(i == 1)
    return y;

    if(i == 2)
    return z;


    ;


    I tossed this into Compiler Explorer (https://godbolt.org/z/0X4FPL), which showed clang optimizing the operator[] call away at -O2, and GCC at -O3. Less exciting than your approach, but simple and should work under most circumstances.






    share|improve this answer




















    • 1





      Well, this will be optimized only when i is known at compile time, right? godbolt.org/z/evVGPZ

      – freakish
      7 hours ago












    • True! What you are getting in your example is definitely less efficient than the optimal. However, in most applications with a fixed-size array, I imagine it would be uncommon for there to be situations where a specific index cannot be known at compile time. Either an index will be supplied as a literal, or there will be loops over [0,2]. This is of course highly application sensitive, so the anonymous structs/unions proposed by @Xirema is probably the best way to go.

      – youngmit
      7 hours ago















    4
















    If this is going to live in a header, and you have some confidence in your compiler's optimizing capabilities, you can probably stick to a plain-old operator[]() overload and expect the compiler to be smart enough to elide the call and return the element that you want. E.g.:



    class Vec3f 
    public:
    float x;
    float y;
    float z;

    float &operator[](int i)
    if(i == 0)
    return x;

    if(i == 1)
    return y;

    if(i == 2)
    return z;


    ;


    I tossed this into Compiler Explorer (https://godbolt.org/z/0X4FPL), which showed clang optimizing the operator[] call away at -O2, and GCC at -O3. Less exciting than your approach, but simple and should work under most circumstances.






    share|improve this answer




















    • 1





      Well, this will be optimized only when i is known at compile time, right? godbolt.org/z/evVGPZ

      – freakish
      7 hours ago












    • True! What you are getting in your example is definitely less efficient than the optimal. However, in most applications with a fixed-size array, I imagine it would be uncommon for there to be situations where a specific index cannot be known at compile time. Either an index will be supplied as a literal, or there will be loops over [0,2]. This is of course highly application sensitive, so the anonymous structs/unions proposed by @Xirema is probably the best way to go.

      – youngmit
      7 hours ago













    4














    4










    4









    If this is going to live in a header, and you have some confidence in your compiler's optimizing capabilities, you can probably stick to a plain-old operator[]() overload and expect the compiler to be smart enough to elide the call and return the element that you want. E.g.:



    class Vec3f 
    public:
    float x;
    float y;
    float z;

    float &operator[](int i)
    if(i == 0)
    return x;

    if(i == 1)
    return y;

    if(i == 2)
    return z;


    ;


    I tossed this into Compiler Explorer (https://godbolt.org/z/0X4FPL), which showed clang optimizing the operator[] call away at -O2, and GCC at -O3. Less exciting than your approach, but simple and should work under most circumstances.






    share|improve this answer













    If this is going to live in a header, and you have some confidence in your compiler's optimizing capabilities, you can probably stick to a plain-old operator[]() overload and expect the compiler to be smart enough to elide the call and return the element that you want. E.g.:



    class Vec3f 
    public:
    float x;
    float y;
    float z;

    float &operator[](int i)
    if(i == 0)
    return x;

    if(i == 1)
    return y;

    if(i == 2)
    return z;


    ;


    I tossed this into Compiler Explorer (https://godbolt.org/z/0X4FPL), which showed clang optimizing the operator[] call away at -O2, and GCC at -O3. Less exciting than your approach, but simple and should work under most circumstances.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered 8 hours ago









    youngmityoungmit

    3943 silver badges11 bronze badges




    3943 silver badges11 bronze badges










    • 1





      Well, this will be optimized only when i is known at compile time, right? godbolt.org/z/evVGPZ

      – freakish
      7 hours ago












    • True! What you are getting in your example is definitely less efficient than the optimal. However, in most applications with a fixed-size array, I imagine it would be uncommon for there to be situations where a specific index cannot be known at compile time. Either an index will be supplied as a literal, or there will be loops over [0,2]. This is of course highly application sensitive, so the anonymous structs/unions proposed by @Xirema is probably the best way to go.

      – youngmit
      7 hours ago












    • 1





      Well, this will be optimized only when i is known at compile time, right? godbolt.org/z/evVGPZ

      – freakish
      7 hours ago












    • True! What you are getting in your example is definitely less efficient than the optimal. However, in most applications with a fixed-size array, I imagine it would be uncommon for there to be situations where a specific index cannot be known at compile time. Either an index will be supplied as a literal, or there will be loops over [0,2]. This is of course highly application sensitive, so the anonymous structs/unions proposed by @Xirema is probably the best way to go.

      – youngmit
      7 hours ago







    1




    1





    Well, this will be optimized only when i is known at compile time, right? godbolt.org/z/evVGPZ

    – freakish
    7 hours ago






    Well, this will be optimized only when i is known at compile time, right? godbolt.org/z/evVGPZ

    – freakish
    7 hours ago














    True! What you are getting in your example is definitely less efficient than the optimal. However, in most applications with a fixed-size array, I imagine it would be uncommon for there to be situations where a specific index cannot be known at compile time. Either an index will be supplied as a literal, or there will be loops over [0,2]. This is of course highly application sensitive, so the anonymous structs/unions proposed by @Xirema is probably the best way to go.

    – youngmit
    7 hours ago





    True! What you are getting in your example is definitely less efficient than the optimal. However, in most applications with a fixed-size array, I imagine it would be uncommon for there to be situations where a specific index cannot be known at compile time. Either an index will be supplied as a literal, or there will be loops over [0,2]. This is of course highly application sensitive, so the anonymous structs/unions proposed by @Xirema is probably the best way to go.

    – youngmit
    7 hours ago











    1
















    GLM implements this kind of functionality using anonymous structs inside an anonymous union



    I can't personally guarantee that this is standard-compliant, but most major compilers (MSVC, GCC, Clang) will support this idiom:



    struct Vector3f 
    union
    struct
    float x, y, z;
    ;
    struct
    float data[3];
    ;
    ;
    Vector3f() : Vector3f(0,0,0)
    Vector3f(float x, float y, float z) : x(x), y(y), z(z)
    ;

    int main()
    Vector3f vec;
    vec.x = 14.5;
    std::cout << vec.data[0] << std::endl; //Should print 14.5
    vec.y = -22.345;
    std::cout << vec.data[1] << std::endl; //Should print -22.345
    std::cout << sizeof(vec) << std::endl; //On most platforms will print 12



    The non-standard behavior is in the anonymous struct used to group the letters together, which GCC will issue a warning about. As far as I know, the union itself should be valid, because the datatypes are all identical, but you should still check with your compiler documentation if you're unsure whether this is valid or not.



    As an added convenience, we can also overload the brackets operator to shorten our syntax a little:



    struct Vector3f 
    /*...*/
    float& operator[](size_t index) return data[index];
    float operator[](size_t index) const return data[index];
    ;



    int main()
    Vector3f vec;
    vec.x = 14.5;
    std::cout << vec[0] << std::endl; //Should print 14.5
    vec.y = -22.345;
    std::cout << vec[1] << std::endl; //Should print -22.345
    std::cout << sizeof(vec) << std::endl; //On most platforms will print 12




    Just for clarity, accessing inactive members in the way I am is valid according to the C++ standard, because those members share a "common subsequence":




    If two union members are standard-layout types, it's well-defined to examine their common subsequence on any compiler.



    CPP Reference: Union Declaration




    Because x and data[0] are



    • Both floats,

    • Both occupy the same memory,

    • Are both standard Layout types as the standard defines them,

    It's perfectly valid to access one or the other regardless of which is currently active.






    share|improve this answer






















    • 1





      This is UB. C++ (unlike C) does not allow accessing other union members once initialized with one.

      – freakish
      8 hours ago







    • 1





      @freakish It does if (and only if) the types of the inactive union members are the same as the active members and occupy the same memory.

      – Xirema
      8 hours ago











    • @Xirema it is technically UB from a standards perspective. However AFAIK all compilers have chosen to define the behavior for compatibility reasons (within reason). Unless you're thinking that "compatible types" makes this OK...

      – Mgetz
      8 hours ago







    • 3





      it's UB and uses two GNU extensions a) anonymous struct not allowed by ISO . b) union type punning works. Not ALL compilers support that, but GNU collections works in non-strict mode. Xinera misquotes clause, because it relates to stucts with common begin, which isn't the case here.

      – Swift - Friday Pie
      8 hours ago







    • 3





      common sequence doesn't apply here.. it would have applied if both members were standard-layout ctypes with equivalent declarations. Either two arrays or two structs. SO it's technically type punning, because way how array is aligned may be (platform defined) different from struct.. especially if certain pragmas were used in code.

      – Swift - Friday Pie
      8 hours ago
















    1
















    GLM implements this kind of functionality using anonymous structs inside an anonymous union



    I can't personally guarantee that this is standard-compliant, but most major compilers (MSVC, GCC, Clang) will support this idiom:



    struct Vector3f 
    union
    struct
    float x, y, z;
    ;
    struct
    float data[3];
    ;
    ;
    Vector3f() : Vector3f(0,0,0)
    Vector3f(float x, float y, float z) : x(x), y(y), z(z)
    ;

    int main()
    Vector3f vec;
    vec.x = 14.5;
    std::cout << vec.data[0] << std::endl; //Should print 14.5
    vec.y = -22.345;
    std::cout << vec.data[1] << std::endl; //Should print -22.345
    std::cout << sizeof(vec) << std::endl; //On most platforms will print 12



    The non-standard behavior is in the anonymous struct used to group the letters together, which GCC will issue a warning about. As far as I know, the union itself should be valid, because the datatypes are all identical, but you should still check with your compiler documentation if you're unsure whether this is valid or not.



    As an added convenience, we can also overload the brackets operator to shorten our syntax a little:



    struct Vector3f 
    /*...*/
    float& operator[](size_t index) return data[index];
    float operator[](size_t index) const return data[index];
    ;



    int main()
    Vector3f vec;
    vec.x = 14.5;
    std::cout << vec[0] << std::endl; //Should print 14.5
    vec.y = -22.345;
    std::cout << vec[1] << std::endl; //Should print -22.345
    std::cout << sizeof(vec) << std::endl; //On most platforms will print 12




    Just for clarity, accessing inactive members in the way I am is valid according to the C++ standard, because those members share a "common subsequence":




    If two union members are standard-layout types, it's well-defined to examine their common subsequence on any compiler.



    CPP Reference: Union Declaration




    Because x and data[0] are



    • Both floats,

    • Both occupy the same memory,

    • Are both standard Layout types as the standard defines them,

    It's perfectly valid to access one or the other regardless of which is currently active.






    share|improve this answer






















    • 1





      This is UB. C++ (unlike C) does not allow accessing other union members once initialized with one.

      – freakish
      8 hours ago







    • 1





      @freakish It does if (and only if) the types of the inactive union members are the same as the active members and occupy the same memory.

      – Xirema
      8 hours ago











    • @Xirema it is technically UB from a standards perspective. However AFAIK all compilers have chosen to define the behavior for compatibility reasons (within reason). Unless you're thinking that "compatible types" makes this OK...

      – Mgetz
      8 hours ago







    • 3





      it's UB and uses two GNU extensions a) anonymous struct not allowed by ISO . b) union type punning works. Not ALL compilers support that, but GNU collections works in non-strict mode. Xinera misquotes clause, because it relates to stucts with common begin, which isn't the case here.

      – Swift - Friday Pie
      8 hours ago







    • 3





      common sequence doesn't apply here.. it would have applied if both members were standard-layout ctypes with equivalent declarations. Either two arrays or two structs. SO it's technically type punning, because way how array is aligned may be (platform defined) different from struct.. especially if certain pragmas were used in code.

      – Swift - Friday Pie
      8 hours ago














    1














    1










    1









    GLM implements this kind of functionality using anonymous structs inside an anonymous union



    I can't personally guarantee that this is standard-compliant, but most major compilers (MSVC, GCC, Clang) will support this idiom:



    struct Vector3f 
    union
    struct
    float x, y, z;
    ;
    struct
    float data[3];
    ;
    ;
    Vector3f() : Vector3f(0,0,0)
    Vector3f(float x, float y, float z) : x(x), y(y), z(z)
    ;

    int main()
    Vector3f vec;
    vec.x = 14.5;
    std::cout << vec.data[0] << std::endl; //Should print 14.5
    vec.y = -22.345;
    std::cout << vec.data[1] << std::endl; //Should print -22.345
    std::cout << sizeof(vec) << std::endl; //On most platforms will print 12



    The non-standard behavior is in the anonymous struct used to group the letters together, which GCC will issue a warning about. As far as I know, the union itself should be valid, because the datatypes are all identical, but you should still check with your compiler documentation if you're unsure whether this is valid or not.



    As an added convenience, we can also overload the brackets operator to shorten our syntax a little:



    struct Vector3f 
    /*...*/
    float& operator[](size_t index) return data[index];
    float operator[](size_t index) const return data[index];
    ;



    int main()
    Vector3f vec;
    vec.x = 14.5;
    std::cout << vec[0] << std::endl; //Should print 14.5
    vec.y = -22.345;
    std::cout << vec[1] << std::endl; //Should print -22.345
    std::cout << sizeof(vec) << std::endl; //On most platforms will print 12




    Just for clarity, accessing inactive members in the way I am is valid according to the C++ standard, because those members share a "common subsequence":




    If two union members are standard-layout types, it's well-defined to examine their common subsequence on any compiler.



    CPP Reference: Union Declaration




    Because x and data[0] are



    • Both floats,

    • Both occupy the same memory,

    • Are both standard Layout types as the standard defines them,

    It's perfectly valid to access one or the other regardless of which is currently active.






    share|improve this answer















    GLM implements this kind of functionality using anonymous structs inside an anonymous union



    I can't personally guarantee that this is standard-compliant, but most major compilers (MSVC, GCC, Clang) will support this idiom:



    struct Vector3f 
    union
    struct
    float x, y, z;
    ;
    struct
    float data[3];
    ;
    ;
    Vector3f() : Vector3f(0,0,0)
    Vector3f(float x, float y, float z) : x(x), y(y), z(z)
    ;

    int main()
    Vector3f vec;
    vec.x = 14.5;
    std::cout << vec.data[0] << std::endl; //Should print 14.5
    vec.y = -22.345;
    std::cout << vec.data[1] << std::endl; //Should print -22.345
    std::cout << sizeof(vec) << std::endl; //On most platforms will print 12



    The non-standard behavior is in the anonymous struct used to group the letters together, which GCC will issue a warning about. As far as I know, the union itself should be valid, because the datatypes are all identical, but you should still check with your compiler documentation if you're unsure whether this is valid or not.



    As an added convenience, we can also overload the brackets operator to shorten our syntax a little:



    struct Vector3f 
    /*...*/
    float& operator[](size_t index) return data[index];
    float operator[](size_t index) const return data[index];
    ;



    int main()
    Vector3f vec;
    vec.x = 14.5;
    std::cout << vec[0] << std::endl; //Should print 14.5
    vec.y = -22.345;
    std::cout << vec[1] << std::endl; //Should print -22.345
    std::cout << sizeof(vec) << std::endl; //On most platforms will print 12




    Just for clarity, accessing inactive members in the way I am is valid according to the C++ standard, because those members share a "common subsequence":




    If two union members are standard-layout types, it's well-defined to examine their common subsequence on any compiler.



    CPP Reference: Union Declaration




    Because x and data[0] are



    • Both floats,

    • Both occupy the same memory,

    • Are both standard Layout types as the standard defines them,

    It's perfectly valid to access one or the other regardless of which is currently active.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited 7 hours ago

























    answered 8 hours ago









    XiremaXirema

    16.2k3 gold badges20 silver badges54 bronze badges




    16.2k3 gold badges20 silver badges54 bronze badges










    • 1





      This is UB. C++ (unlike C) does not allow accessing other union members once initialized with one.

      – freakish
      8 hours ago







    • 1





      @freakish It does if (and only if) the types of the inactive union members are the same as the active members and occupy the same memory.

      – Xirema
      8 hours ago











    • @Xirema it is technically UB from a standards perspective. However AFAIK all compilers have chosen to define the behavior for compatibility reasons (within reason). Unless you're thinking that "compatible types" makes this OK...

      – Mgetz
      8 hours ago







    • 3





      it's UB and uses two GNU extensions a) anonymous struct not allowed by ISO . b) union type punning works. Not ALL compilers support that, but GNU collections works in non-strict mode. Xinera misquotes clause, because it relates to stucts with common begin, which isn't the case here.

      – Swift - Friday Pie
      8 hours ago







    • 3





      common sequence doesn't apply here.. it would have applied if both members were standard-layout ctypes with equivalent declarations. Either two arrays or two structs. SO it's technically type punning, because way how array is aligned may be (platform defined) different from struct.. especially if certain pragmas were used in code.

      – Swift - Friday Pie
      8 hours ago













    • 1





      This is UB. C++ (unlike C) does not allow accessing other union members once initialized with one.

      – freakish
      8 hours ago







    • 1





      @freakish It does if (and only if) the types of the inactive union members are the same as the active members and occupy the same memory.

      – Xirema
      8 hours ago











    • @Xirema it is technically UB from a standards perspective. However AFAIK all compilers have chosen to define the behavior for compatibility reasons (within reason). Unless you're thinking that "compatible types" makes this OK...

      – Mgetz
      8 hours ago







    • 3





      it's UB and uses two GNU extensions a) anonymous struct not allowed by ISO . b) union type punning works. Not ALL compilers support that, but GNU collections works in non-strict mode. Xinera misquotes clause, because it relates to stucts with common begin, which isn't the case here.

      – Swift - Friday Pie
      8 hours ago







    • 3





      common sequence doesn't apply here.. it would have applied if both members were standard-layout ctypes with equivalent declarations. Either two arrays or two structs. SO it's technically type punning, because way how array is aligned may be (platform defined) different from struct.. especially if certain pragmas were used in code.

      – Swift - Friday Pie
      8 hours ago








    1




    1





    This is UB. C++ (unlike C) does not allow accessing other union members once initialized with one.

    – freakish
    8 hours ago






    This is UB. C++ (unlike C) does not allow accessing other union members once initialized with one.

    – freakish
    8 hours ago





    1




    1





    @freakish It does if (and only if) the types of the inactive union members are the same as the active members and occupy the same memory.

    – Xirema
    8 hours ago





    @freakish It does if (and only if) the types of the inactive union members are the same as the active members and occupy the same memory.

    – Xirema
    8 hours ago













    @Xirema it is technically UB from a standards perspective. However AFAIK all compilers have chosen to define the behavior for compatibility reasons (within reason). Unless you're thinking that "compatible types" makes this OK...

    – Mgetz
    8 hours ago






    @Xirema it is technically UB from a standards perspective. However AFAIK all compilers have chosen to define the behavior for compatibility reasons (within reason). Unless you're thinking that "compatible types" makes this OK...

    – Mgetz
    8 hours ago





    3




    3





    it's UB and uses two GNU extensions a) anonymous struct not allowed by ISO . b) union type punning works. Not ALL compilers support that, but GNU collections works in non-strict mode. Xinera misquotes clause, because it relates to stucts with common begin, which isn't the case here.

    – Swift - Friday Pie
    8 hours ago






    it's UB and uses two GNU extensions a) anonymous struct not allowed by ISO . b) union type punning works. Not ALL compilers support that, but GNU collections works in non-strict mode. Xinera misquotes clause, because it relates to stucts with common begin, which isn't the case here.

    – Swift - Friday Pie
    8 hours ago





    3




    3





    common sequence doesn't apply here.. it would have applied if both members were standard-layout ctypes with equivalent declarations. Either two arrays or two structs. SO it's technically type punning, because way how array is aligned may be (platform defined) different from struct.. especially if certain pragmas were used in code.

    – Swift - Friday Pie
    8 hours ago






    common sequence doesn't apply here.. it would have applied if both members were standard-layout ctypes with equivalent declarations. Either two arrays or two structs. SO it's technically type punning, because way how array is aligned may be (platform defined) different from struct.. especially if certain pragmas were used in code.

    – Swift - Friday Pie
    8 hours ago












    0
















    As stated, this is impossible: pointer arithmetic is defined only within an array, and there’s no way (without putting a reference in the class, which takes up space in current implementations) to have v.x refer to an array element.






    share|improve this answer





























      0
















      As stated, this is impossible: pointer arithmetic is defined only within an array, and there’s no way (without putting a reference in the class, which takes up space in current implementations) to have v.x refer to an array element.






      share|improve this answer



























        0














        0










        0









        As stated, this is impossible: pointer arithmetic is defined only within an array, and there’s no way (without putting a reference in the class, which takes up space in current implementations) to have v.x refer to an array element.






        share|improve this answer













        As stated, this is impossible: pointer arithmetic is defined only within an array, and there’s no way (without putting a reference in the class, which takes up space in current implementations) to have v.x refer to an array element.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered 7 hours ago









        Davis HerringDavis Herring

        12.2k1 gold badge8 silver badges37 bronze badges




        12.2k1 gold badge8 silver badges37 bronze badges
























            0
















            There's no need for reinterpret_cast, nor unions. You can define a simple operator[]:



            struct Vector3f 
            float x, y, z;
            float& operator[](std::size_t i)return *(&x + i);
            ;


            If you want a strong guarantee that this will work, though, you need to make sure that your class is Standard Layout. In practice, it should work in most cases, even if it's not. For instance, don't add any virtual functions to this class.






            share|improve this answer

























            • Pointer arithmetic cannot be used to move from one member to another, only within arrays.

              – Davis Herring
              3 hours ago















            0
















            There's no need for reinterpret_cast, nor unions. You can define a simple operator[]:



            struct Vector3f 
            float x, y, z;
            float& operator[](std::size_t i)return *(&x + i);
            ;


            If you want a strong guarantee that this will work, though, you need to make sure that your class is Standard Layout. In practice, it should work in most cases, even if it's not. For instance, don't add any virtual functions to this class.






            share|improve this answer

























            • Pointer arithmetic cannot be used to move from one member to another, only within arrays.

              – Davis Herring
              3 hours ago













            0














            0










            0









            There's no need for reinterpret_cast, nor unions. You can define a simple operator[]:



            struct Vector3f 
            float x, y, z;
            float& operator[](std::size_t i)return *(&x + i);
            ;


            If you want a strong guarantee that this will work, though, you need to make sure that your class is Standard Layout. In practice, it should work in most cases, even if it's not. For instance, don't add any virtual functions to this class.






            share|improve this answer













            There's no need for reinterpret_cast, nor unions. You can define a simple operator[]:



            struct Vector3f 
            float x, y, z;
            float& operator[](std::size_t i)return *(&x + i);
            ;


            If you want a strong guarantee that this will work, though, you need to make sure that your class is Standard Layout. In practice, it should work in most cases, even if it's not. For instance, don't add any virtual functions to this class.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered 6 hours ago









            Cássio RenanCássio Renan

            3,87419 silver badges47 bronze badges




            3,87419 silver badges47 bronze badges















            • Pointer arithmetic cannot be used to move from one member to another, only within arrays.

              – Davis Herring
              3 hours ago

















            • Pointer arithmetic cannot be used to move from one member to another, only within arrays.

              – Davis Herring
              3 hours ago
















            Pointer arithmetic cannot be used to move from one member to another, only within arrays.

            – Davis Herring
            3 hours ago





            Pointer arithmetic cannot be used to move from one member to another, only within arrays.

            – Davis Herring
            3 hours ago


















            draft saved

            draft discarded















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f57810925%2fconvenient-vector3f-class%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            ParseJSON using SSJSUsing AMPscript with SSJS ActivitiesHow to resubscribe a user in Marketing cloud using SSJS?Pulling Subscriber Status from Lists using SSJSRetrieving Emails using SSJSProblem in updating DE using SSJSUsing SSJS to send single email in Marketing CloudError adding EmailSendDefinition using SSJS

            Кампала Садржај Географија Географија Историја Становништво Привреда Партнерски градови Референце Спољашње везе Мени за навигацију0°11′ СГШ; 32°20′ ИГД / 0.18° СГШ; 32.34° ИГД / 0.18; 32.340°11′ СГШ; 32°20′ ИГД / 0.18° СГШ; 32.34° ИГД / 0.18; 32.34МедијиПодациЗванични веб-сајту

            19. јануар Садржај Догађаји Рођења Смрти Празници и дани сећања Види још Референце Мени за навигацијуу