6

The following seems perfectly logical to me, but isn't valid c++. A union cannot be implicitly cast to one of it's member types. Anyone know a good reason why not?

union u {
  int i;
  char c;
}
function f(int i) {
}
int main() {
  u v;
  v.i = 6;
  f(v);
}

And can anyone suggest a clean alternative (the cleanest I can come up with is f(v.i);, which I admit is very clean, but the above just seems even cleaner)

timrau
  • 22,578
  • 4
  • 51
  • 64
Baruch
  • 20,590
  • 28
  • 126
  • 201

5 Answers5

13

While agreeing with Crazy Eddie that it doesn't look that better to me you can actually get an implicit conversion by defining it:

union u {
    int i;
    char c;
    operator int () const { return i; }
    operator char () const { return c; }
};
6502
  • 112,025
  • 15
  • 165
  • 265
  • 1
    I feel inclined to downvote, implicit conversions are a source of more problems than advantages and at the same time it only solves part of the problem, as it will allow `f(v)` if the argument of `f` is either an `int` or a `const int&` but will fail with `int&`. Also, if the function stores the reference (case of `const int&`) that will not refer to `v.i`, but rather to the temporary --will die at the end of the full expression, will not get updated as `u.i` gets modified... which might lead to unexpected behaviours – David Rodríguez - dribeas Feb 20 '11 at 23:12
  • 1
    I agree that is a bad idea and I'd never use this stuff but it's what the original poster was asking for (an implicit cast from union to a member) and may be that in his/her use case is a meaningful thing to do. Note that all the problems you list are also present when passing an `int` to a function expecting a `double` or a `const double&`. – 6502 Feb 20 '11 at 23:49
  • 1
    Yes, I agree. You've solved the OPs problem, and do not deserve to be downvoted. However, it's highly questionable as to whether or not the OP should be doing that in the first place. – Omnifarious Feb 21 '11 at 07:54
  • @Omnifarious then in my opinion someone should downvote or comment the question and not correct answers – ToxiCore Nov 21 '16 at 17:39
5

The reason why this isn't available implicitly (by default) is that it can be ambiguous. It's completely legal to have more than one member with the same type, and there would be no reason to prefer one or the other.

union u
{
    char c;
    TCHAR t;
    wchar_t w;
    int i;
};
void f(TCHAR);

u v;
f(v); // which member should be used?
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • 7
    If there was one or more member of the same type, it wouldn't matter which one the compiler used, since they all occupy exactly the same space. – dreamlax Feb 20 '11 at 22:15
  • 4
    @dreamlax: A valid point, in all practical implementations. Unfortunately according to the standard it does matter. – Ben Voigt Feb 20 '11 at 22:22
4

How would the compiler know which member to use? It would need to keep track of which member was last assigned so it knows what to convert to. This is called a tagged union, and while it's certainly possible for the language to specify such a thing, that's not the case (it's a hold-over from C).

But that's okay, because we have boost::variant. Not only is it safer and more flexible than a union, it's more powerful. You can apply visitors to the variant, and it'll call (visit) the specified function with whichever member is currently active, with no further work from the user.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • No, it wouldn't. It is perfectly legal to assign to one member and read a different one. – Baruch Feb 20 '11 at 22:24
  • 4
    @baruch: You're *exactly* wrong. In fact, the very first sentence describing unions is: "In a union, at most one of the data members can be active at any time, that is, the value of at most one of the data members can be stored in a union at any time." It's undefined behavior to write to one member than read from another. – GManNickG Feb 20 '11 at 22:35
  • 1
    One possible source of confusion is that C and C++ differ in this respect. Reading a different member than the one last assigned is encouraged in C's standard. – Alex Celeste Sep 22 '15 at 04:24
1

There is no different syntax I am familiar with. To be honest, accessing the union member directly is rather clear and concise as is.

I assume the reason there is no implicit casting is because of some rule whereby it's technically "undefined behavior" to write to one member of a union, then read from another member.

The implicitly casted type may not be the last one written to. While it's perfectly compilable code and it would probably work fine, the compiler, in principle, should not automatically or implicitly do something that is against the very rules it enforces.

Sion Sheevok
  • 4,057
  • 2
  • 21
  • 37
0

Anyone know a good reason why not?

function f(char c) {
    doStuff(c);
}

Best reason I can think of.

And can anyone suggest a clean alternative?

I'm with Crazy Eddie on this one; f(v.i) is as "clean" as it gets without inviting programmer errors. Two extra characters is an acceptable price to pay for more robust code, no?

Cheezmeister
  • 4,895
  • 3
  • 31
  • 37