用户定义的类型 - 单位、转换
User defined types - units, conversions
我尝试制作一些用户定义的类型来表示单位,以便我可以强键入函数参数。 例如,毫米表示长度
,毫米每秒表示速度,每秒毫米表示加速度,等等。到目前为止,我已经这样做了:
template<typename T, typename mksUnit>
struct Value
{
// data member
T val;
// constructor
constexpr explicit Value(T d) : val(d) {}
// operator overloads
Value & operator +=(const Value &rhs) { val += rhs.val; return *this; }
// other math and compare
// operators, etc.
}
template<int meters, int kilo, int seconds>
struct mksUnit
{
enum { m = meters, k = kilo, s = seconds };
};
有了这个,我可以做这样的事情:
using meters = Value<double, mksUnit<1, 0, 0>>;
using mm = Value<double, mksUnit<-3, 0, 0>>;
constexpr mm operator""_mm(long double v) { return mm(static_cast<double>(v)); }
using mmpersec = Value<double, mksUnit<-3, 0, 1>>;
constexpr mmpersec operator""_mms(long double v) { return mmpersec(static_cast<double>(v)); }
using mmpersec2 = Value<double, mksUnit<-3, 0, 2>>;
constexpr mmpersec2 operator""_mms2(long double v) { return mmpersec2(static_cast<double>(v)); }
创建我可以使用的单位,例如:
mm dist = 5.5_mm;
mm dist1 = dist + 10_mm;
mmpersec velocity = mmpersec(50.0);
mmpersec2 accel = 100.0_mms2;
void set_accel(mmpersec2 accel) { _accel = accel; }
等。
我需要在某些类型之间进行转换,我正在寻找一种好方法。 我唯一的想法是从类继承并将类型重载添加到派生类中。
struct millimeters: public mm
{
operator(meters) { return mm.val / 1000; }
}
或类似的东西。
我想做这样的事情:
meters len = meters(5.0);
len += millimeters(25);
例如,这应该将 len 设置为 1.025。
我的问题是,在派生的不同用户定义类型之间添加转换的最佳方法是什么,如上所示。
我认为你从错误的方向解决问题。您不想变换任意单位,而是变换数量内的单位。
所以我会这样开始:
struct Quantity {
double value;
};
// Base Quantites
class Length : public Quantity {};
class Duration : public Quantity {};
// Base units
Length Meter() {
Length l;
l.value = 1;
return l;
}
Length Millimeter() {
Length l;
l.value = 0.001;
return l;
}
Duration Seconds() {
Duration t;
t.value = 1;
return t;
}
现在我们整理了数量,我们可以开始转换了:
// It is a good Idea to use SFINAE here to enable this function
// only for derived classes of Quantity
template <class Quantity>
double transform(Quantity&& value, Quantity&& ratio) {
return value.value / ratio.value;
}
派生单位的部分是棘手的:
template <class Q1, class Q2>
struct MultipliedQuantiy : public Quantity {};
// I would use SFINAE here too because it is a bad idea to
// define a multiplication for all possible types.
template <class Q1, class Q2>
auto operator*(Q1 q1, Q2 q2) {
MultipliedQuantiy<Q1, Q2> q;
q.value = q1.value * q2.value;
return q;
}
作为一个例子,我们可以使用它:
auto area = 1000.0*Millimeter()*(1000.0*Millimeter());
auto squareMeter = 1.0*Meter()*Meter();
double area_in_m2 = transform(area, squareMeter);
所以这是基本的想法,关于如何做到这一点。其余操作由您决定。你也可以在很多地方使用 constexpr 来强制编译时求值。
相关文章:
- 防止主数据类型C++的隐式转换
- 模板参数替换失败,并且未完成隐式转换
- 用户定义的转换顺序(以C++为单位)
- 以C++为单位将毫秒转换为小时:分钟:秒:毫秒
- 以秒为单位将时间从纪元转换为一年中的某一天?
- 这里怎么了?单位转换器
- put_time具有转换说明符,该转换指定符,该指定符在一个月的单个数字上输出没有前面字符的单位天数
- 以部门为单位的类型转换
- 以C++为单位将每 5 位转换为整数值
- 用户定义的类型 - 单位、转换
- boost.units中单位的转换因子
- 单位从脚转换为米
- 在 C++ 中以毫秒为单位将日期转换为时间
- 从毫米到公里的转换(以较小的单位溢出,例如米)
- 以C++为单位键入矢量转换
- 将 Unix 时间戳(以毫秒为单位)转换为正常日期
- 将FILETIME转换为便携式时间单位
- 如何使用boost::units添加自己的基本单位和转换
- 在QSqlTableModel中为UI值做单位转换
- 将时间戳(以毫秒为单位)转换为boost中的时区