5

Maybe I'm missing something, but IMO the 4th bullet point in iso §12.1 p5 is wrong:

X is a union and all of its variant members are of const-qualified type (or array thereof),

simply because you can't have more than one const qualified member in a union.

From §9.1 we have:

In a union, at most one of the non-static data members can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time.

Edit:

This snippet doesn't compile in Ideone

union U
{
    const int i;
    const char c;
    float x;
    U(int j, char a) : i(j), c(a) {}
};

Edit1:

The following code compiles in Coliru and Ideone. But according to 12.1 p5 4th bullet point, it shouldn't as the default constructor should be deleted.

#include <iostream>
union T
{
    const int y;
    const int x;
    const float z;
    T(int j) : y(j) {}
    T() = default;
};

int main()
{
    T t;
}

Edit2:

I also don't understand why the Standard disallows this code (see note in 9.5 p2)

struct S
{
    int i;
    S() : i(1) {}
};

union T
{
    S s;
    char c;
};

int main()
{
    T t;
}

but allows this. What's the difference?

struct S
{
    int i;
    S() : i(1) {}
};

union T
{
    S s;
    char c;
    T() {}
};

int main()
{
    T t;
}
timrau
  • 22,578
  • 4
  • 51
  • 64
Wake up Brazil
  • 3,421
  • 12
  • 19

2 Answers2

10

§12.1/5 is perfectly valid: it's just saying that no default constructor can possibly be generated if all the members are const, because then there is no member that can be left uninitialised.

§9.1 says nothing about limiting constness. It is a passage about limitations on accessing the union member's values, which is totally irrelevant.

Only one member being "active" here means that only one can be written to and read from in arbitrary sequence. As soon as you write to another member, you may only read from that member.

Here's an example, and a live demo showing that the example's union declaration is valid:

union T
{
    int x;
    const int y;
    const int z;
};

int main()
{
    T a{4};
    a.x = 5;
    a.y = 6;
    a.z = 7;
}

// $ g++-4.8 -std=c++11 -Wall -pedantic -pthread main.cpp && ./a.out
// main.cpp: In function 'int main()':
// main.cpp:14:9: error: assignment of read-only member 'T::y'
//      a.y = 6;
//          ^
// main.cpp:15:9: error: assignment of read-only member 'T::z'
//      a.z = 7;
//          ^

Live demo

Since compilation succeeds right up to the attempted assignment of T::y.


Edit: The code you've now pasted, and the error message you're complaining about, have nothing to do with the const.

initializations for multiple members of ‘U’

That is your problem. It says so right there! It makes no sense to try to initialise both members of a union, since only one may be "active" at any given time:

[C++11: 12.6.2/8]: [..] An attempt to initialize more than one non-static data member of a union renders the program ill-formed. [..]

But this has nothing at all to do with constness.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • ... and with C++11 if the active member isn't a standard layout type you also need to destroy the active member before replacing it. – Dietmar Kühl Dec 27 '13 at 18:59
  • what are the typical use cases for the union you showed above? if only one member in read/writable and I modify it then cant use the other const members right?. – Koushik Shetty Jan 03 '14 at 11:19
  • @Koushik: That's .. a good point. You can only use one of the `const` fields, once, and only if it was the initialised field! – Lightness Races in Orbit Jan 03 '14 at 14:17
7

§9.1 says/does nothing to prevent you from having multiple const members in a union.

Although it does a poor job of stating the limitation (at least IMO) all §9.1 really says is that at any given time, only one field of a union contains a meaningful value--specifically, the field that was initialized when the union was created or the field to which a value was assigned the most recently.

Now, it's certainly true that if all the members of the union are const, you won't be able to assign to any of them, so that latter provision becomes moot. That limits what you can do with such a union after it exists, but doesn't prevent you from creating such a union to start with.

The effect of 12.1/5b4 is that if all the members of the union are const, you can't just define an instance of that union without specifying an initializer, either by explicitly defining a ctor, or else by specifying an initializer when you create the instance:

union X { 
    const int a;
    const double b;
};

X x;   // won't compile

X x(2); // no problem -- x.a == 2

union Y { 
   const int a;
   const double b;

   Y() : b(0.0) {}
};

Y y;  // no problem: uses user defined ctor

The end result is that const gives roughly the same behavior applied to something inside a union as it does to things elsewhere--just for example, you can't define an object like:

const int x;

...either. You need to specify an initializer to create it:

const int x = 20;

The code you've added really is about §9.1 though, not about 12.1/5 at all. Since only one member of the union can be active at any given time, it only makes sense to initialize one member. Attempting to initialize two members would imply that both those members could hold values, but in fact only one can hold a value at any one time.

Edit: As to 12.1/5b4 applying only when all the members are const-qualified, I think that also makes sense. For example code like this:

union Z {
    int a;
    const double b;
};

Z z;

z.a = 1;

Seems perfectly acceptable. Admittedly, since it hasn't been initialized, you can never actually use Z.b in this case, but that's more or less beside the point--there's still no particularly good reason for the compiler to prevent default construction.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • But what about the sentence in 12.1: `A defaulted default constructor for class X is defined as deleted if: ... X is a union and all of its variant members are of const-qualified type (or array thereof), ... ` – Wake up Brazil Dec 27 '13 at 19:20
  • @WakeupBrazil: Completely irrelevant--in your union, `U.x` isn't of const-qualified type, so that bullet doesn't apply to your code at all. – Jerry Coffin Dec 27 '13 at 19:23
  • Just forget about my code. I was just trying to give credit to my claim that the 4th bullet point is wrong (although using a mistaken example). I'm concerned about the correctness of the 4th bullet point in 12.1 ! – Wake up Brazil Dec 27 '13 at 19:24
  • @WakeupBrazil: I believe it's correct. The snippet I've shown in my answer demonstrates what it means and why it makes sense. – Jerry Coffin Dec 27 '13 at 19:26
  • `[C++11: 12.6.2/8]:` _[..]_ An attempt to initialize more than one non-static data member of a union renders the program ill-formed. _[..]_ – Lightness Races in Orbit Dec 27 '13 at 19:27
  • @LightnessRacesinOrbit: Thanks -- hadn't caught that. – Jerry Coffin Dec 27 '13 at 19:28
  • @WakeupBrazil: I don't understand why you think it's "wrong". By definition, this is a rule of the language. It is neither inconsistent with text elsewhere in the standard, nor illogical. – Lightness Races in Orbit Dec 27 '13 at 19:30
  • I must tell you that your last snippet doesn't compile in Ideone (http://ideone.com/AthF2n) – Wake up Brazil Dec 27 '13 at 21:37
  • @WakeupBrazil: Fair enough, but I don't see anything in the standard mandating that behavior. – Jerry Coffin Dec 27 '13 at 21:58
  • But then again, I continue with my doubts about the 4th bullet point in 12.1 ! For me it should be written as: `A defaulted default constructor for class X is defined as deleted if: ... X is a union and at least two of its variant members are of const-qualified type (or array thereof)`. – Wake up Brazil Dec 27 '13 at 22:20
  • @WakeupBrazil: I have different doubts, primarily about the advisability of using unions in C++ at all. – Jerry Coffin Dec 27 '13 at 22:31
  • I have never used unions before. My main concern is to understand the Standard. – Wake up Brazil Dec 27 '13 at 23:18
  • @WakeupBrazil: My immediate reaction is that almost regardless of how much you know, there are almost certainly other areas to study more profitably. – Jerry Coffin Dec 27 '13 at 23:22