-1

Question about unions, since I rarely use them.

I am using a union to represent rgb pixel data, so it can be accessed as a continual array of uint8_t or as individual rgb elements. (I think this is probably one of the few uses for unions.)

Something like this:

union PixelRGB
{
    uint8_t array[3];
    struct rgb
    {
        uint8_t b;
        uint8_t g;
        uint8_t r;
    };
};

I've realized it would be nice to be able to apply operations like "and" and "or" on my pixel data. I'd like to do something like

PixelRGB::operator&=(const PixelRGB other)
{
    this->rgb.r = other.r;
    this->rgb.g = other.g;
    this->rgb.b = other.b;
}

I tried putting an operator like this in the union but as far as I'm aware that's not allowed in C++. (I also got a compiler error when compiling - so from this I assume it is not allowed.)

One possible solution I've considered is wrapping the union in a class and then adding operators to that class. This is somewhat unpleasant with namespace/name-scope however.

Are there any other solutions?

timrau
  • 22,578
  • 4
  • 51
  • 64
FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225
  • I suspect the way you are using a union is undefined behavior. – Eljay Dec 25 '18 at 20:09
  • `struct rgb {...};` seems to be a typo. If you replace it with `struct {...} rgb;` then you indeed get UB. – HolyBlackCat Dec 25 '18 at 20:11
  • @HolyBlackCat why is it UB? – FreelanceConsultant Dec 25 '18 at 20:36
  • More precisely, it's doesn't give you UB immediately, but rather when you try to access an inactive union member: https://stackoverflow.com/questions/11373203/accessing-inactive-union-member-and-undefined-behavior – HolyBlackCat Dec 25 '18 at 20:39
  • @HolyBlackCat I'm confused, so in my example code above, if I access a different member other than the last one set it *is* UB? (C++11/14/17 ?) – FreelanceConsultant Dec 25 '18 at 20:42
  • If you *read* from a member different than the one that was last written to, then yes, you get UB. In all C++ standards. – HolyBlackCat Dec 25 '18 at 20:45
  • @HolyBlackCat Ok I'll ask a new question about this – FreelanceConsultant Dec 25 '18 at 20:48
  • @HolyBlackCat Asked my question - it got immediatly closed, but the linked duplicate which imo isn't duplicate suggests this is NOT UB. What do you think? https://stackoverflow.com/questions/53925554/c-i-think-my-union-may-be-producing-undefined-behaviour?noredirect=1#comment94692703_53925554 – FreelanceConsultant Dec 25 '18 at 21:03
  • The linked [answer](https://stackoverflow.com/a/36080743/2752075) doesn't say it's not UB. That answer provides a standard quote that would've made it well-defined if it was applicable, but the answer says that the quote doesn't apply in that case. – HolyBlackCat Dec 25 '18 at 21:39

2 Answers2

3

You can define the operator inside the union, it's possible

union PixelRGB {
    ...
    PixelRGB& operator&=(const PixelRGB& other) {
        return *this;
    }
};

or outside

PixelRGB& operator&=(PixelRGB& self, const PixelRGB& other) {
    return self;
}
Jans
  • 11,064
  • 3
  • 37
  • 45
  • Worth noting that the compiler error received was likely because the asker left out the operator's return type. – user4581301 Dec 25 '18 at 20:16
  • @user4581301 It's very likely – Jans Dec 25 '18 at 20:17
  • 1
    @user4581301 - the OP's code as shown did not even declare the operator within the class definition, but tried to define it outside. That would not work. – Peter Dec 25 '18 at 20:19
  • Yeah it was just pseduocode guys - but what I have in my actual code is quite similar – FreelanceConsultant Dec 25 '18 at 20:36
  • 1
    @user3728501 Try to be as exact as possible otherwise you will get answers focused on the minutia that the example gets wrong that may have been right in the original code. – user4581301 Dec 25 '18 at 20:40
0

The problem is not with the operator, but with way you access the union. You can try this combination:

union PixelRGB
{
    uint8_t array[3];
    struct {
        uint8_t b;
        uint8_t g;
        uint8_t r;
    };
};


PixelRGB& operator&=(PixelRGB& self, const PixelRGB& other) {
    self.r = other.r;
    self.g = other.g;
    self.b = other.b;

    return self;
}

or this:

union PixelRGB
{
    uint8_t array[3];
    struct {
        uint8_t b;
        uint8_t g;
        uint8_t r;
    };

    PixelRGB& operator&=( const PixelRGB& other) {
        r = other.r;
        g = other.g;
        b = other.b;

        return *this;
    }
};

or this:

union PixelRGB
{
    uint8_t array[3];
    struct {
        uint8_t b;
        uint8_t g;
        uint8_t r;
    };

    PixelRGB& operator&=( const PixelRGB& other);
};


PixelRGB& PixelRGB::operator&=( const PixelRGB& other) {
    r = other.r;
    g = other.g;
    b = other.b;

    return *this;
}

Note: anonymous struct has been introduced in C11

https://en.cppreference.com/w/c/language/struct

but it is not standard in C++ even though it is supported by multiple compilers.

Victor Padureanu
  • 604
  • 1
  • 7
  • 12
  • Handy reading: [Why does C++ disallow anonymous structs?](https://stackoverflow.com/questions/2253878/why-does-c-disallow-anonymous-structs) – user4581301 Dec 25 '18 at 20:36