Michael Sims
Michael Sims

Reputation: 2533

Can a C++ union perform math on the number it contains?

Is it possible in C++ to create a union that would let me do something like this ...

union myTime {
    long millis;
    double seconds;
};

BUT, have it somehow do the conversion so that if I input times in milliseconds, and then call seconds, it will take the number and divide it by 1000, or conversely, if I input the number in seconds, then call millis, it would multiply the number by 1000...

So that:

myTime.millis = 1340;

double s = myTime.seconds;

Where s would equal 1.34

or

myTime.seconds = 2.5;

long m = myTime.millis;

Where m would = 2500

Is this possible?

Upvotes: 1

Views: 176

Answers (3)

Chris Dodd
Chris Dodd

Reputation: 126418

You can if you abuse the type system a bit:

union myTime {
    double seconds;
    class milli_t {
        double seconds;
     public:
        milli_t &operator=(double ms) {
            seconds = ms/1000.0;
            return *this; }
        operator double() const { return seconds * 1000; }
    } millis;
};

Now if you do

myTime t;
t.millis = 1340;
double s = t.seconds;

s would equal 1.34

and

myTime t;
t.seconds = 2.5;
long m = t.millis;

m would be 2500, exactly as you desire.

Of course, why you would want to do this is unclear.

Upvotes: 1

Bitwize
Bitwize

Reputation: 11230

To answer the question as asked: No. Unions are lower-level structure that simply allow multiple object representations to live in the same memory space. In your example, long and double share the same address.

They are not, however, smart enough to automatically do a conversation of any kind. Accessing the inactive member of a union is actually undefined behavior in most cases (there are exceptions for if you have a common-initial sequence in a standard-layout object).

Even if the behavior were well-defined, the value you would see in the double would be the double interpretation of the byte-pattern necessary to represent 1340.


If your problem is specifically to do with converting millis to seconds, as per your example, have you considered using std::chrono::duration units? These units are designed specifically for automatically doing these conversions between time units for you -- and you are capable of defining durations with custom representations (such as double).

Your example in your problem could be rewritten:

using double_seconds = std::chrono::duration<double>;
const auto millis = std::chrono::millis{1340};

const auto m = double_seconds{millis}; 

// m contains 1.340

Upvotes: 1

user107511
user107511

Reputation: 822

A union is just different representations for the same value (the same bytes), so you can't define any smart logic over that.

In this case, you can define a class with conversion functions (both for initializtion or for getting the data).

class myTime {
public:
    myTime(long millis);
    double as_seconds();

    static void from_seconds(double seconds);
};

Notice that as mentioned in other answers, for time conversions you can use std::chrono objects (c++11 and above)

Upvotes: 3

Related Questions