4

Is it possible define a union temporary inside the function call, rather than defining it previously and then passing it in the parameters?

Example:

           union data_t{
            double delaySeconds;
            float scale;
            float rotation;

            };

           void someFunction(data_t){}

Now I want to call someFunction, using whatever element of the union is appropriate:

            someFunction(WHAT DO I PUT HERE);

For example, if you are passing to a function that expects a type that includes a constructor, you can define your temporary right there in the function call. But I've tried a variety of ways with this union with no luck. For example, suppose I want to pass a float assigned to scale:

          someFunction(data_t.scale(2.0));
johnbakers
  • 24,158
  • 24
  • 130
  • 258
  • 2
    If it were me, I would avoid `union` like the plague. – Roger Rowland May 11 '13 at 06:39
  • 1
    not necessarily ... unions can be very powerful if used correctly – Ahmed Masud May 11 '13 at 06:40
  • 5
    Why don't you use overloading? – Pubby May 11 '13 at 06:40
  • @AhmedMasud - given that the OP tagged this with C++, can you give an example? – Roger Rowland May 11 '13 at 06:41
  • sure :) happy to ... I'll add it at the tail end of the answer – Ahmed Masud May 11 '13 at 06:46
  • 1
    @Pubby more likely the better solution would be to use a template for this. I just want to avoid writing a bunch of overloaded functions, especially if `data_t` has more than a few of these potential contents – johnbakers May 11 '13 at 06:57
  • 1
    @Fellowshee: I'm with Pubby on this. A function that can take either seconds, or angles, or a scaling factor _sounds_ like a design problem - you'll need to do some manual dispatching inside the function, and you can't do that with a union, there's no way to tell which of the members was initialized. (And templates doesn't seem to be the right tool either). Overloading or simply having different functions for the different actions required sounds saner. – Mat May 11 '13 at 07:01
  • @Mat whether you overload and create several different functions, or you dispatch within one large "parent" function, you are still writing multiple directions code can go based on an input type. This union is actually part of a grander structure I've shown in another question, but simplified in this question since the points you make are a bit aside from my question. The other question is here http://stackoverflow.com/questions/16494845/all-public-struct-yields-call-to-implicitly-deleted-default-constructor – johnbakers May 11 '13 at 07:31
  • @Fellowshee: my point above is that in one case, the compiler does the dispatching for you (with all the checks it can do), in the other you do it manually. I'm not saying there are no cases where the design you've got is the right thing to do. Plus unions are fiendishly tricky in C++ (http://stackoverflow.com/questions/11373203/accessing-inactive-union-member-undefined). (Again, not saying what you have _will_ lead you to that sort of problem. Just that it can.) – Mat May 11 '13 at 07:36

1 Answers1

2

You can define a constructor for your union for initializing the members. But, you need a mechanism to distinguish which field was set. Below, I define a helper enum, and extend your data_t to allow for inheritance and member distinction.

enum data_t_type { DelaySeconds, Scale, Rotation };

struct data_t {
    union {
        double delaySeconds;
        float scale;
        float rotation;
    };
    union {
        unsigned char flags;
        struct {
            unsigned char isDelaySeconds : 1;
            unsigned char isScale : 1;
            unsigned char isRotation : 1;
        };
    };
    data_t () : flags(0) {}
};

Now, the initialization is actually done with a template that takes the data_t_type as a parameter.

template <data_t_type> struct data_type {};

template <> struct data_type<DelaySeconds> : data_t {
    data_type (double x) { delaySeconds = x; isDelaySeconds = 1; }
};

template <> struct data_type<Scale> : data_t {
    data_type (float x) { scale = x; isScale = 1; }
};

template <> struct data_type<Rotation> : data_t {
    data_type (float x) { rotation = x; isRotation = 1; }
};

So now, you can call your function like so:

someFunction(data_type<Scale>(2.0));

Since a data_type<> is a data_t, someFunction() gets the right type.

jxh
  • 69,070
  • 8
  • 110
  • 193
  • interestingly this is similar to what i've done, but i encountered a related issue here: http://stackoverflow.com/questions/16494845/all-public-struct-yields-call-to-implicitly-deleted-default-constructor – johnbakers May 11 '13 at 07:32
  • `vec3` is probably your problem. – jxh May 11 '13 at 07:36
  • Search for *bitfield* or *bit field* in your C++ programming reference. – jxh May 11 '13 at 07:37
  • this answer is quite an interesting solution to my question, thank you. – johnbakers May 11 '13 at 07:42
  • I've been searching for a while to see what your colon syntax means in `unsigned char isDelaySeconds : 1;` but I cannot. Is that some sort of substitute for = for chars? – johnbakers Nov 04 '15 at 16:20