Enum class for weight units I have some enum classes for units, like Weight units (KG and LB). I am translating the code to Qt C++ from Java, and I'm wondering what the best way to do this is as enums cannot have constructors in C++ that same way they do in Java (as far as I know).

Here is the Java class:


public enum WeightUnit {
  LB(WEIGHT_UNIT_LB, 0.45359237), //"lb" 1lb = 0.45359237 kg.
  KG(WEIGHT_UNIT_KG, 1.0);        //"kg"

  private String displayName;
  private double scale;

  private WeightUnit(String displayNameKey, double scale) {
      this.displayName = getDataMessages().getString(displayNameKey);
      this.scale = scale;
  }

  public String getDisplayName() {
      return displayName;
  }

  public String toString() {
      return displayName;
  }

  public static WeightUnit valueByName(String unitName) {
      for (WeightUnit value : WeightUnit.values()) {
          if (value.getDisplayName().equals(unitName) ||
                  value.name().equals(unitName)) {
              return value;
          }
      }
      throw new IllegalArgumentException(unitName);
  }

  public static double convert(double value, WeightUnit from, WeightUnit to) {
      if (from == to) return value;
      return value * from.scale/to.scale;
  }
}



Here is my C++ translation. It is not as elegant or clean as the Java version.

class WeightUnit {
  public:
    enum Value
    {
        LB,
        KG
    };

    WeightUnit() = default;
    constexpr WeightUnit(Value weightUnit) : value(weightUnit) {}

    bool operator==(WeightUnit a) const { return value == a.value; }
    bool operator!=(WeightUnit a) const { return value != a.value; }

    static double convert(double value, WeightUnit fromUnit, WeightUnit toUnit){
        return value * val(fromUnit.value)/val(toUnit.value);
    }

    static WeightUnit fromStr(QString str){
        if (str.compare(toStr(Value::LB)) == 0)
            return WeightUnit::LB;
        else if (str.compare(toStr(Value::KG)) == 0)
            return WeightUnit::KG;
        else
            throw QException();
    }

    static QString toStr(WeightUnit unit){
        if (unit == WeightUnit::LB)
            return "lb";
        else if (unit == WeightUnit::KG)
            return "kg";
        else
            throw QException();
    }

private:
    Value value;

    static double val(Value value){
        switch(value){
        case KG:
            return 1.0;
        case LB:
            return 0.45359237; //1 lb = 0.45359237 kg
        }
        throw QException(); //if not found, throw exception
    }
};


Is there any better way to tie values to each enum value in C++? In Java it is easy, because you can specify a constructor that requires certain parameters so you can be sure each enum value has an appropriate String and double value. Is there a way to do this in Qt/C++?
Even if Java and C++ display some similarities, particularly in the syntax, they are widely different languages and translating one into the other isn't automatic. Java is chiefly object-oriented, while C++ is more of a multi-paradigm language; one could even argue that it's drifting away from the object-oriented model towards a more functional approach designed to take advantage of compile-time customization and calculations.

So, it's best to take a step back and think again about your objectives and the means you have to achieve them when you transition from one to the other.

What you seem to need is a mapping between a unit, a textual representation and a floating precision proportion. Java allows for float based enums, which are thus a good candidate -even if the textual representation needs to be addressed somewhere else- but C++ doesn't. On the other hand, in the most recent version of the C++ standard, you can create and manipulate arrays at compile-time:

constexpr std::pair&lt;std::string_view, float&gt; weight_units[] {
    { "kg", 1. },
    { "lb", 0.45359237 },
    { "oz", 0.028349523125 },
};

constexpr auto weight_unit_value(std::string_view unit) {
    return std::find_if(std::begin(weight_units), std::end(weight_units), [unit](auto uv) {
        return uv.first == unit;
    })-&gt;second;
}


This code sadly compiles only with the latest version of clang, because gcc hasn't implemented the constexpr version of the standard algorithms yet. But writing it by hand would take 5 minutes. Or you can simply remove the constexpr qualifier.

This code has several advantages over the original Java version, the most important being that everything is defined once in one place. If you want to create a new unit in the original code, you need to modify the enum and create a new object with a custom name; here, you just extend the array.

Now, the array is also very handy if you want to parse a weight from a string, or convert a weight to a string:

// ex: float weight = parse_weight("1204.3 lb");
auto parse_weight(std::string_view weight) {
    auto coeff =  std::find_if(std::begin(weight_units), std::end(weight_units), [weight](auto uv) {
        return weight.ends_with(uv.first);
    })-&gt;second;
    return std::stof(weight.data()) * coeff;
}

auto to_string(float value, std::string_view unit_name) {
    auto result = std::to_string(value / weight_unit_value(unit_name));
    auto out = std::back_inserter(result);
    *out++ = ' ';
    std::copy(unit_name.begin(), unit_name.end(), out);
    return result;
}


Error handling could be added very easily (auto found = std::find_if(...); if (found == std::end(units)) throw unknown_unit("blabla");

Here's some code to toy with: https://wandbox.org/permlink/zj0hckfk6jR0vrXT