模板元编程技术的一个最基本应用:为传统的不进行类型检查的操作添加静态类型检查。
以物理计算为例,物理中的数值常常不是独立存在的,它们往往带有量纲。所以不仅有数值的计算,还有量纲的计算。如两个不同量纲的数值的加减往往是没有意义的,而不同量纲数值的乘除计算得到的结果往往是不同的物理量。将量纲看为类型,那么在物理数值计算中进行静态类型检查是很有意义的。举例如下:
/************************************************************************* > File Name: physical_quantity.cpp > Author: corfox > Mail: [email protected] > Created Time: 2015/12/31 22:26:22 ************************************************************************/
#include <iostream>
#include <cassert>
#include <type_traits>
using namespace std;
namespace pq {
template<int v>
struct Int
{
static const int value = v;
};
// 定义一个量纲模板类
template<typename T, int v1, int v2, int v3, int v4, int v5, int v6, int v7>
struct Dimension
{
static const int d1 = v1;
static const int d2 = v2;
static const int d3 = v3;
static const int d4 = v4;
static const int d5 = v5;
static const int d6 = v6;
static const int d7 = v7;
typedef T value_type;
};
// 外包一层(Traits技术),以便物理量乘除计算时,能获得计算结果的新量纲
template<typename T1, typename T2>
struct DimensionOperation
{
typedef Dimension<typename T1::value_type, T1::d1 + T2::d1, T1::d2 + T2::d2,
T1::d3 + T2::d3, T1::d4 + T2::d4, T1::d5 + T2::d5,
T1::d6 + T2::d6, T1::d7 + T2::d7> plus_type;
typedef Dimension<typename T1::value_type, T1::d1 - T2::d1, T1::d2 - T2::d2,
T1::d3 - T2::d3, T1::d4 - T2::d4, T1::d5 - T2::d5,
T1::d6 - T2::d6, T1::d7 - T2::d7> minus_type;
};
// 特化一些常用量纲
typedef Dimension<int, 1, 0, 0, 0, 0, 0, 0> Mass;
typedef Dimension<int, 0, 1, 0, 0, 0, 0, 0> Length;
typedef Dimension<int, 0, 0, 1, 0, 0, 0, 0> Time;
typedef Dimension<int, 0, 0, 0, 1, 0, 0, 0> Charge;
typedef Dimension<int, 0, 0, 0, 0, 1, 0, 0> Temperature;
typedef Dimension<int, 0, 0, 0, 0, 0, 1, 0> Intensity;
typedef Dimension<int, 0, 0, 0, 0, 0, 0, 1> AmountOfSubstance;
typedef Dimension<int, 0, 1, -1, 0, 0, 0, 0> Velocity;
typedef Dimension<int, 0, 1, -2, 0, 0, 0, 0> Acceleration;
typedef Dimension<int, 1, 1, -1, 0, 0, 0, 0> Momentum;
typedef Dimension<int, 1, 1, -2, 0, 0, 0, 0> Force;
template<typename T, typename D>
class Quantity
{
private:
T value;
public:
explicit Quantity(T v) : value(v) {}
T getValue() const { return value; }
friend ostream& operator<<(ostream& out, const Quantity& y)
{
out << y.getValue();
return out;
}
friend Quantity operator+(const Quantity& x, const Quantity& y)
{
return Quantity(x.getValue() + y.getValue());
}
friend Quantity operator-(const Quantity& x, const Quantity& y)
{
return Quantity(x.getValue() - y.getValue());
}
};
template<typename T, typename D1, typename D2>
Quantity<T, typename DimensionOperation<D1, D2>::plus_type>
operator*(const Quantity<T, D1>& x, const Quantity<T, D2>& y)
{
return Quantity<T, typename DimensionOperation<D1, D2>::plus_type>(x.getValue() + y.getValue());
}
template<typename T1, typename D1, typename D2>
Quantity<T1, typename DimensionOperation<D1, D2>::minus_type>
operator/(const Quantity<T1, D1>& x, const Quantity<T1, D2>& y)
{
return Quantity<T1, typename DimensionOperation<D1, D2>::minus_type>(x.getValue() + y.getValue());
}
}
int main()
{
pq::Quantity<float, pq::Length> l1(1.0f);
pq::Quantity<float, pq::Length> l2(2.0f);
pq::Quantity<float, pq::Mass> m1(3.0f);
cout << l1 + l2 << endl;
cout << l1 - l2 << endl;
cout << l1 * l2 << endl;
cout << l1 / l2 << endl;
cout << l1 * m1 << endl;
// cout << l1 + m1 << endl;
return 0;
}