Efficient way to overload float type in C++?

136 Views Asked by At

I would like to store quantities such as weight, time, length. I suppose this way is more readable and avoid mismatch in such function:

Velocity computeSpeed(Distance d, Time t);

Currently I only have

using float_type = double;
using Velocity = float_type;
using Distance = float_type;
using Time = float_type;

However, for my application I need some conversions such as:

Distance toInches(Distance);
Distance toMillimeters(Distance);

I rather wanted to have something like:

Distance d;
std::cout << d.toInches();

However, overloading base types may have some drawbacks:

  • It requires to overload all operators or use a CRTP on float type
  • This may impact the efficiency

Is it possible to add "conversion" const methods to numeric types? Side question: is this approach bad or overkill?

NOTE: I am stuck with C++03 :(

3

There are 3 best solutions below

0
Mike Nakis On

I have done what you are trying to do in C#, which has far fewer overloading capabilities than C++. The result is awesome, since it protects you from all kinds of mistakes and keeps the code terse and to the point. (It eliminates incidental complexity.)

It also allows your IDE's completion suggestions feature to shine, because it will show you what you can do with each variable, instead of having to know by heart which global-scope functions are applicable to each variable.

The way to do it is to declare a new class for each different type of quantity, which contains a single value in some standard unit. (And you will, of course, choose the SI system for your standard units, right?)

Once you have these classes, you can overload all the applicable operators so that they work between instances of each class and between every combination that makes sense.

If you like living your life dangerously you can even use the amazing ability of C++ to overload the type-cast operator, so that you can directly assign float to an instance of a quantity, hoping (praying) that the float is in the right unit. My advice would be that you don't do that, and instead you create static methods like Length::ofMeters( float ), Length::ofInches( float ) etc.

0
MSalters On

Your idea isn't entirely new; this has been proposed around 2001.

The main issue with your design is that Distance toInches(Distance); and Distance toMillimeters(Distance); do exactly the same thing. You can both implement them as Distance toFoo(Distance bar) { return bar };

The reason is that 1 inch is 2.54 mm. They're literally the same Distance.

What you could have is float toInches(Distance d), with the obvious implementation float toInches(Distance d) { return d/Distanche::inch; } with Distance::inch being a constant equal to 2.54 mm.

These types need to be classes, because you need template argument math. And you really need to do this in SI, because Velocity=Distance/Duration. Only SI units are sane enough for this. Unit<m1,kg1,s1>/Unit<m2,kg2,s2>=Unit<m1-m2,kg1-kg2,s1-s2>, and Distance is just a typedef for Unit<1,0,0>.

0
Leon On

Since your variables describe some sort of physical property i'd suggest you to create a type for each of them yourself, one the most powerful capabilities of C++ is that you can define your own type (OOP), then you'll use basic types under the hood, and provide functionalities to them such as conversion. .toInches() and overload operators for them, for example I use my own type of vector3d and I overloaded operator* for it so that I can multiply it my a matrix like so vector3d operator*(const matrix3x3& mat) also added functionalities like unsigned int Length() const to get the length of the vector.