Question

I am looking for a solution using the C++03 standard (I am constrained to using this version of the standard for several years yet). Solutions for C++11 are also welcome, but will not be "accepted" as the answer to this question.

What is a simple, concise way that I can represent a set of related constant floating point values as a single type (similar to an enum) to ensure type-safety without incurring significant overhead and still allow me to operate on the values as floats directly?

The end result is that I would like to be able to do something like the following:

enum FloatingPointEnum
{
   VALUE1 = 0.1234f,
   ...
   VALUEN = 0.6789f
};


float SomeFunction(FloatingPointEnum value)
{
    float new_value;
    /* perform some operation using "value" to calculate "new_value" */
    new_value = static_cast<float>(value); // <- a simplistic example
    return new_value;
}

While I can think of several solutions, none of them are as clean/simple/straightforward as I would like and I figure that someone must already have an elegant solution to this problem (yet I cannot seem to find one in my searching).

EDIT:

I would like the following call to SomeFunction with a value that is not specified directly as a value from the enumerated type to fail to compile:

float nonEnumeratedValue = 5.0f
SomeFunction(nonEnumeratedValue);
Was it helpful?

Solution

someone must already have an elegant solution to this problem

There are lots of problems that have no elegant solution (and many that have no solution at all). What makes you think this problem has one? The closest you can get is to use a wrapper class.

class FloatingPointEnum {
    float f;
    FloatingPointEnum(float arg) : f(arg) {}
public:
    static const FloatingPointEnum Value1;
    static const FloatingPointEnum Value2;
    operator float() const { return f; }
};
const FloatingPointEnum FloatingPointEnum::Value1(0.1234f);
const FloatingPointEnum FloatingPointEnum::Value2(0.6789f);

OTHER TIPS

A possible alternative solution, not always applicable but very clean, is to use fixed precision.

Lets imagine you have you enum containing some distance in meters

enum DistancesMeter{
 A = 0.25,
 b = 0.05,
};

then you may simply switch to use mm

enum DistancesMM{
 A = 250,
 b = 50,
};

In C++11 you can use constexpr to achieve what you want.

constexpr - specifies that the value of a variable or function can appear in constant expressions

http://en.cppreference.com/w/cpp/language/constexpr

With constexpr you define a compile-time constant. This only works for literal types, such as float. Since at the same time we want

float nonEnumeratedValue = 5.0f;
SomeFunction(nonEnumeratedValue);

to fail, we cannot use a simple typedef. Instead we use Boost’s BOOST_STRONG_TYPEDEF.

#include <boost/serialization/strong_typedef.hpp>

BOOST_STRONG_TYPEDEF(float, FloatingPointEnum);
constexpr float VALUE1 = 0.1234f;
constexpr float VALUEN = 0.6789f;

float SomeFunction(FloatingPointEnum value)
{
  float new_value;
  /* perform some operation using "value" to calculate "new_value" */
  new_value = static_cast<float>(value); // <- a simplistic example
  return new_value;
}

Now you can call the function only with instances of FloatingPointEnum. Unfortunately, the instantiation syntax is not so nice anymore

FloatingPointEnum f {VALUEN};

Alternatively, you can simply use the D programming language, where floating point enums are supported and the following code works as expected:

enum FloatingPointEnum
{
   VALUE1 = 0.1234f,
   //...
   VALUEN = 0.6789f
};


float SomeFunction(FloatingPointEnum value)
{
    float new_value;
    new_value = value; // No cast needed, welcome to D!
    return new_value;
}

Calling SomeFunction with a float results in

Error: function test.SomeFunction (FloatingPointEnum value) is not callable using argument types (float)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top