Jer*_*unh 6 c++ design-patterns
我最近正在阅读关于C++ Source的系列文章,"暂停反思:五个五个列表".在第五部分中,Scott Meyers讨论了Barton和Nackman解决单位问题的方法.作为航空航天业的嵌入式软件工程师,这个特别的啊哈!片刻让我很兴奋.到目前为止,我还没有听说过这种方法(也没有这些作者).
我已经做过研究,试图找到有关该解决方案的更多信息.我在这里看到了这个演讲:http://se.ethz.ch/~meyer/publications/OTHERS/scott_meyers/dimensions.pdf
我想我理解了我在这个解决方案上所阅读的所有内容.但我觉得有一块拼图丢失了.这个美丽,优雅的解决方案无处可扩展.具体来说,我对转换不仅仅是一个倍增因素感兴趣.例如,温度在开尔文,摄氏和华氏之间转换.我希望能够互换使用这些温度.
我的问题:
我错过了什么?是否参考了我忽略的单位解决方案讨论,在某处讨论了规模?
如果没有,我怎么能进一步解决这个问题?是否存在可与B&N方法结合使用以完成解决方案的现有模式?
我的目标是能够在没有过多计算的情况下使用类似下面示例的代码.在距离的情况下,我希望能够声明一个定义为英里的对象,并以英里为单位执行所有相关计算,而不必经常来回转换为米.
例:
typedef Units<double, miles> uMiles;
typedef Units<double, kilometers> uKilometers;
uMiles d1 (1.0);
uKilometers d2 (1.60934);
d1 += d2;
if (d1.val(miles) == 2.0) // PASS
if (d1.val(kilometers) == 3.21869) // PASS
Run Code Online (Sandbox Code Playgroud)
注意:我已经看到了BOOST UNITS解决问题的方法,我不喜欢它.对我来说这是非常难以理解的.我也不是,通常允许使用外部库,如boost.
资料备份:
单位类如下所述:
template<class T, // Precision
int m, // Mass
int l, // Length
int t, // Time
int q, // Charge
int k, // Temperature
int i, // Luminous Intensity
int a> // Angle
class Units
{
public:
// ------------------------------------------------------
explicit
Units (T initVal = 0)
: val (initVal)
{
}
// --------------------------------------------------------------------
// Operator: Assignment from type T
Units<T, m, l, t, q, k, i, a>&
operator= (const T rhs)
{
val = rhs;
return *this;
}
// --------------------------------------------------------------------
// Operator: Type Converstion to T
operator T () const
{
return val;
}
// --------------------------------------------------------------------
// Operator: +=
Units<T, m, l, t, q, k, i, a>&
operator+= (const Units<T, m, l, t, q, k, i, a>& rhs)
{
val += rhs.val;
return *this;
}
// --------------------------------------------------------------------
Units<T, m, l, t, q, k, i, a>&
operator-= (const Units<T, m, l, t, q, k, i, a>& rhs)
{
val -= rhs.val;
return *this;
}
// --------------------------------------------------------------------
Units<T, m, l, t, q, k, i, a>&
operator*= (T rhs)
{
val *= rhs;
return *this;
}
// --------------------------------------------------------------------
Units<T, m, l, t, q, k, i, a>&
operator/= (T rhs)
{
val /= rhs;
return *this;
}
// --------------------------------------------------------------------
// Get Reference
T&
Val ()
{
return val;
}
// --------------------------------------------------------------------
// Get Value
const T&
Val () const
{
return val;
}
private:
T val;
};
// ----------------------------------------------------------------------------
// Operator: Addition
template<class T, int m, int d, int t, int q, int k, int i, int a>
const Units<T, m, d, t, q, k, i, a>
operator+ (const Units<T, m, d, t, q, k, i, a> & lhs,
const Units<T, m, d, t, q, k, i, a> & rhs)
{
Units<T, m, d, t, q, k, i, a> result (lhs);
return result += rhs;
}
// ----------------------------------------------------------------------------
// Operator: Subtraction
template<class T, int m, int d, int t, int q, int k, int i, int a>
const Units<T, m, d, t, q, k, i, a>
operator- (const Units<T, m, d, t, q, k, i, a> & lhs,
const Units<T, m, d, t, q, k, i, a> & rhs)
{
Units<T, m, d, t, q, k, i, a> result (lhs);
return result -= rhs;
}
// ----------------------------------------------------------------------------
// Operator: Multiplication
template<class T, int m, int d, int t, int q, int k, int i, int a>
const Units<T, m, d, t, q, k, i, a>
operator* (const Units<T, m, d, t, q, k, i, a> & lhs,
const Units<T, m, d, t, q, k, i, a> & rhs)
{
Units<T, m, d, t, q, k, i, a> result (lhs);
return result *= rhs;
}
// ----------------------------------------------------------------------------
// Operator: Division
template<class T, int m, int d, int t, int q, int k, int i, int a>
const Units<T, m, d, t, q, k, i, a>
operator/ (const Units<T, m, d, t, q, k, i, a> & lhs,
const Units<T, m, d, t, q, k, i, a> & rhs)
{
Units<T, m, d, t, q, k, i, a> result (lhs);
return result /= rhs;
}
// ----------------------------------------------------------------------------
// Operator: Multiplication (Creates New Type)
template<class T,
int m1, int d1, int t1, int q1, int k1, int i1, int a1,
int m2, int d2, int t2, int q2, int k2, int i2, int a2>
// Return Type
Units<T, m1 + m2, d1 + d2, t1 + t2, q1 + q2, k1 + k2, i1 + i2, a1 + a2>
operator* (const Units<T, m1, d1, t1, q1, k1, i1, a1>& lhs,
const Units<T, m2, d2, t2, q2, k2, i2, a2>& rhs)
{
// New Return type
typedef Units<T,
m1 + m2,
d1 + d2,
t1 + t2,
q1 + q2,
k1 + k2,
i1 + i2,
a1 + a2> ResultType;
return ResultType (lhs.Val() * rhs.Val());
}
// ----------------------------------------------------------------------------
// Operator: Division (Creates New Type)
template<class T,
int m1, int d1, int t1, int q1, int k1, int i1, int a1,
int m2, int d2, int t2, int q2, int k2, int i2, int a2>
// Return Type
Units<T, m1 - m2, d1 - d2, t1 - t2, q1 - q2, k1 - k2, i1 - i2, a1 - a2>
operator/ (const Units<T, m1, d1, t1, q1, k1, i1, a1>& lhs,
const Units<T, m2, d2, t2, q2, k2, i2, a2>& rhs)
{
// New Return type
typedef Units<
T,
m1 - m2,
d1 - d2,
t1 - t2,
q1 - q2,
k1 - k2,
i1 - i2,
a1 - a2> ResultType;
return ResultType (lhs.Val() / rhs.Val());
}
Run Code Online (Sandbox Code Playgroud)
这个类允许我们编写如下代码:
// Base Types
typedef Units<double, 1,0,0,0,0,0,0> uMass;
typedef Units<double, 0,1,0,0,0,0,0> uLength;
typedef Units<double, 0,0,1,0,0,0,0> uTime;
typedef Units<double, 0,0,0,1,0,0,0> uCharge;
typedef Units<double, 0,0,0,0,1,0,0> uTemperature;
typedef Units<double, 0,0,0,0,0,1,0> uIntensity;
typedef Units<double, 0,0,0,0,0,0,1> uAngle;
// Derived Types
typedef Units<double, 0,2, 0,0,0,0,0> uArea;
typedef Units<double, 0,3, 0,0,0,0,0> uVolume;
typedef Units<double, 0,1,-1,0,0,0,0> uVelocity;
typedef Units<double, 0,1,-2,0,0,0,0> uAcceleration;
typedef Units<double, 1,1,-2,0,0,0,0> uForce;
uMass mass;
uTime time;
uForce force;
uLength length;
uVelocity velocity;
uAcceleration acceleration;
// This will compile
mass = 7.2;
acceleration = 3.5;
force = mass * acceleration;
// These will not compile ** Enforcing Dimensional Unit Correctness
force = 7.2 * acceleration;
force = mass;
force *= acceleration;
Run Code Online (Sandbox Code Playgroud)
根据我对您的代码和解释的理解,您似乎可以定义转换常量“ Units”,例如
Units<double,0,0,0,0,0,0,0> K2C(243.15);
Units<double,0,0,0,0,1,0,0> uCelsius;
Units<double,0,0,0,0,1,0,0> uKelvin;
uCelsius = uKelvin - K2C;
Run Code Online (Sandbox Code Playgroud)
上面的代码与重载运算符一起使用,同时保持模板化单位一致。您必须Unit为要使用的任何常量创建伪变量。
我可以看到的另一种工作方式是编写一个类似的函数
typdef enum {
CELSIUS,
KELVIN,
FAHRENHEIT
} temp_t;
void Units::convertTemp(const temp_t from, const temp_t to) {
switch(from) {
case KELVIN:
val -= 243.15;
case CELSIUS:
if(to == FAHRENHEIT)
//conversion
else if(to == KELVIN)
val += 243.15;
break;
case FAHRENHEIT:
// convert to celsius
if(to == KELVIN)
//convert to Kelvin
}
}
Run Code Online (Sandbox Code Playgroud)