Use of Union with reference
Asked Answered
C

3

10

At work I've been using linux and the GCC compiler for C++11 and C++14. In some of the code at work, I've used a union to store both a reference and a pointer, as so: (Simplified to just the important parts)

struct MyStruct
{
    //Stuff
    union { double& x; double* x_ptr; };
    MyStruct(double& value) : x(value) {}
    //More stuff
};

I believe this code is clear, readable, unambiguous, and provides a convenient way to store references which can be shifted to something else. It provides easily understandable syntactic sugar without costing performance while improving readability. When I attempted to use code like this in visual studio 15, however, the code failed to compile due to "an illegal union member of type double&".

  1. Is this code illegal under the standard, or just under Visual Studio 2015?
  2. Can I MAKE it compile in Visual Studio 2015, or submit a bug report/change request/something?
  3. Is use of a union in that way bad practice?

Note: At my work, pretty much all code is written for Linux and compiled with GCC, and for my specific project, C++11 is guaranteed and GCC is the only compiler that's going to be used.

Edit: Please don't tell me that putting a reference inside a union "has no meaning". When a reference is stored inside a struct, it takes up the same amount of space as a pointer. In addition, the following compiles with clang:

struct MyStruct
{
    //This will compile
    union 
    { 
        struct { double& x; }; 
        double* x_ptr; 
    };
    //This won't compile; WHY?
    /*union 
    { 
        double& x;
        double* x_ptr; 
    };*/
    MyStruct(double& val) : x(val){}
    void Repoint(double& new_value) 
    { 
        x_ptr = &new_value; 
    }
};

Why does it compile when the reference is wrapped in an anonymous struct, but not when it's just in the union?

live example

Contrayerva answered 1/8, 2016 at 4:58 Comment(0)
T
13

In addition to @Brian: You can make it compile by using e.g. std::reference_wrapper instead of a plain reference:

#include <functional>

struct MyStruct
{
    //Stuff
    union { std::reference_wrapper<double> x; double* x_ptr; };
    MyStruct(double& value) : x(value) {}
    //More stuff
};

int main()
{
    double value = 123;
    MyStruct myStruct(value);
}

live example

Thrilling answered 1/8, 2016 at 5:5 Comment(0)
C
11

It is illegal for a union to contain a reference member. This is presumably because references are not objects and it's unspecified whether or not they occupy storage---so it makes little sense for a reference to share its storage with other variables.

A union can have member functions (including constructors and destructors), but not virtual (10.3) functions. A union shall not have base classes. A union shall not be used as a base class. If a union contains a non- static data member of reference type the program is ill-formed.

([class.union]/2)

Caesura answered 1/8, 2016 at 5:3 Comment(2)
When a struct contains a reference, the reference is stored as a pointer. There's no ambiguity.Contrayerva
@JorgePerez It might be. It might also be optimized out in some instances. It is not specified by the standard.Caesura
Q
0

If the standard allowed storing reference types in unions, it would be the only place in the language where, after initializing a reference, you could change the object it refers to:

union U {
   int a;
   int& b;
};

int main() {
   int c = 0, f = 5;
   U x = {.a = 5};
   x.b = c; // Reference points to c
   x.a = 10;
   x.b = f; // Now reference points to f
}

This would break the existing invariants in the standard and compiler implementations.

Quadrille answered 28/8 at 18:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.