Best way to replace enum to maximize compilation check time

I have a pretty old application using different types of currencies. At the moment, currencies are stored in a transfer, for example:

enum CURRENCY {
  EUR,
  USD,
  CNY
};

double convertMoney(CURRENCY in, CURRENCY out, double money_in) {
   ...
}

This works great, but it's actually not safe: I have other functions containing comments, such as WARNING: all inputs should have the same currency. My goal is to replace most of these comments with compile-time checking whenever possible. I can use C ++ 17 and increment.

I thought to use std::variantto:

class EUR {};
class USD {};
class CNY {};

using CURRENCY = std::variant<EUR,USD,CNY>;

template<typename IN, typename OUT>
class Market {
 public:
   ...
   double convertMoney(double in) {
      return in*rate;
   }
 private:
   void updateRate() {
      ....
      rate = some_value_fetched_at_runtime;
   }
   double rate;
};

int main() {
    Market<EUR, USD> eur_usd;
    Market<EUR, CNY> eur_cny;

    std::vector<Market<CURRENCY,CURRENCY>> all_markets{eur_usd, eur_cny};
    ...
    //do something 
    ...
    return 0;
}

But, of course, this will not work, since I'm trying to insert objects of different types into the vector of Market objects.

, , , , enum ++? std::variant , ?

, :

  • - using Markets = std::variant<Market<EUR,USD>,Market<EUR,CNY>,...>, , 100 , .
  • CURRENCY EUR, USD, CNY CURRENCY, v- , . - , , .
  • ( ), .
+4
2
  1. () , , :: std:: chrono :: boost:: unit.

    template< CURRENCY VCurrencyId > class
    t_Sum
    {
        public: using
        t_Value = double;
    
        private: t_Value m_value{};
    
        public: 
        t_Sum(void)
        {}
    
        public: 
        t_Sum(t_Sum const & other)
        :   m_value{other.m_value}
        {}
    
        public: explicit 
        t_Sum(t_Value const & value)
        :   m_value{value}
        {}
    
        public: t_Sum &
        operator =(t_Sum const & other)
        {
            m_value = other.m_value;
            return(*this);
        }
    
        public: t_Value const &
        Get_Value(void)
        {
            return(m_value);
        }
    
        public: void
        Set_Value(t_Value const & value)
        {
            m_value = value;
        }
    };
    
    template< CURRENCY VInputCurrencyId, CURRENCY VOutputCurrencyId > t_Sum< VOutputCurrencyId >
    Convert(t_Sum< VInputCurrencyId > in) {
        ...
    }
    
    using
    t_Eur = t_Sum< EUR >;
    
    using
    t_Usd = t_Sum< USD >;
    
    t_Eur euros{};
    t_Usd bucks{euros};
    // compile-time error, conversion required!
    // or you can add converting constructor
    
+5

- :

enum class CURRENCY {
    EUR = 0,
    USD,
    CNY,
    LAST = CNY     
};

template <CURRENCY cur> class Price;

// Class to handle convertion
class Market
{
public:
    template <CURRENCY Out, CURRENCY In>
    Price<Out> convertMoney(const Price<In>&);

    void updateChange(CURRENCY in, CURRENCY out, double ratio);
private:
    double ratios[int(CURRENCY::Last)][int(CURRENCY::Last)];
};

// Class to represent typed currency value
template <CURRENCY cur>
class Price
{
public:
    explicit Price(double value) : value(value) {}

    // should only be used when we want the value without the type
    double getValue() const { return value; }

    // operation which restrict same currency as
    Price& operator +=(const Price&);
    // ...

private:
    double value;
};
0

Source: https://habr.com/ru/post/1682600/


All Articles