我有一个相当古老的应用程序处理不同种类的货币。目前,货币存储在枚举中,例如:
enum CURRENCY {
EUR,
USD,
CNY
};
double convertMoney(CURRENCY in, CURRENCY out, double money_in) {
...
}
这是伟大的,除了这不是真正的类型安全:我还有其他函数包含 WARNING: all inputs should have the same currency
等注释。我的目标是在可能的情况下通过编译时检查来替换大多数这些注释。我可以使用C ++ 17和boost。
我想过使用std::variant
这样:
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;
}
但是,当然,由于我试图将不同类型的Market对象推送到我的向量中,所以这不会起作用。
总而言之,您认为在现代C ++中替换枚举的最佳方法是什么?如果使用std::variant
是正确的,那么解决上述问题的最佳方法是什么?
请注意:
using Markets = std::variant<Market<EUR,USD>,Market<EUR,CNY>,...>
这样的事情,但这在实践中并不可行,因为我有大约100种市场,这并没有真正提高可维护性。CURRENCY
并拥有EUR
,USD
,CNY
子类CURRENCY
,但这会在运行时使用v-table这会降低编译时间检查的次数。如果有人可以证明我的相反,我会接受它。答案 0 :(得分:5)
您可以将每种货币作为单独的(模板)类,并在它们之间进行显式转换,就像它们在:: 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
答案 1 :(得分:0)
You may do something like:
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;
};