在c ++中使用typedef来获得更多类型的安全性

时间:2018-01-06 04:12:26

标签: c++ c++11

我想重新审视post。目前,我正在努力避免在我的程序中通过混合Rad和Degree类型为角度创建的bug。

例如:

  typedef float Degree;
  typedef float Radian;

  Degree a = 15.;

  Radian b = 3.14/4.;

  float c = a + b;  // no compile error

有新的更新解决方案吗?

编辑01:

我倾向于编写自己的类,因为它的小尺寸和无依赖性。这是工作代码

#include <stdio.h>
#include <iostream>

template<typename numT>
class RadAngle {
public:
    RadAngle() {
      AngVal = 0.0;
    }
    RadAngle(const numT& angV) {
      AngVal = angV;
    }
    void operator = (const RadAngle<numT>& ang1) {
      AngVal = ang1.getVal();
    }
    RadAngle operator+(const RadAngle<numT>& ang1) const { return RadAngle<numT>(AngVal+ang1.getVal()); }
    RadAngle operator-(const RadAngle<numT>& ang1) const { return RadAngle<numT>(AngVal-ang1.getVal()); }
    RadAngle operator*(const RadAngle<numT>& ang1) const { return RadAngle<numT>(AngVal*ang1.getVal()); }
    RadAngle operator/(const RadAngle<numT>& ang1) const { return RadAngle<numT>(AngVal/ang1.getVal()); }

    numT getVal() const { return AngVal;};

private:
    numT AngVal;
};


int main() {

   RadAngle<float> a(1.5);
   RadAngle<float> b(3.14);
   RadAngle<float> c = a+b;

   //std::cout << c << std::endl;
//    printf("%.2f",c.getVal());


   return 0;
}

5 个答案:

答案 0 :(得分:3)

你所拥有的东西根本不能帮助打字安全,除非文件薄弱。就编译器而言,floatDegreeRadian是完整的同义词;这称为弱类型别名。强类型别名不是C ++的一部分,但您可以解决这个问题。有两篇好文章是herehere。基本思想是为强类型dede创建通用类模板,并使用它创建每个单独的别名。

如果您不想自己编写所有样板文件,我建议您使用第三方库来处理此问题。我上面链接的帖子的作者都为它编写了库NamedTypetype_safe。如果你需要更重要的东西,你应该看看Boost.Units。请注意,我自己还没有使用过这些;他们只是在我检查是否需要这些功能的地方。

你没有提出这个问题,但是这一切都不应该只是在任何地方使用float和手动跟踪单位而有任何运行时性能成本,但可能会使编译速度变慢。

答案 1 :(得分:2)

您最好的选择是为每种测量创建一个类,并实现将其转换为另一种的方法。这些类可以/应该有一个共同的超类。

答案 2 :(得分:2)

我会选择一个作为内部表示(例如Radian)并将其他作为包装类

typedef double Radian;
class Degree {
public:
    Degree() {
        m_radian = 0.0;
    }
    Degree(double degree) {
        m_radian = degree / 180.0 * 3.1415926;
    }
    void operator = (double degree) {
        m_radian = degree / 180.0 * 3.1415926;
    }
    operator Radian() const { return m_radian; }
private:
    Radian m_radian;
};

void print_rad(Radian rad) {
   printf("rad: %lf\n", rad);
}

int main() {
   Radian rad = 123.0;
   Degree degree = 456.0;
   print_rad(rad);
   print_rad(degree);
   print_rad(rad + degree);
   return 0;
}

输出:

rad: 123.000000
rad: 7.958701
rad: 130.958701

答案 3 :(得分:1)

我认为你的方法有点缺陷。

您尝试建模的是物理量 - 具有值和单位的类型。

没有数量称为弧度。有一个称为角度的量,其单位可以是弧度或度数。

您需要的是一些基础设施来处理转换数量单位和对单位执行操作以及值。

例如,

L1 = 10 "m" (length)
L2 = 20 "m" (length)

L1 * L2 = 200 "m^2" (area)

F1 = 10 "N" (force)
A1 = 2 "m^2" (area)
F1/A1  = 5 "Pa" (pressure)

A2 = 10 "deg"
convert(A2, "rad") = 0.174533 "rad"

如果您能够添加处理单位的代码,其余功能将很容易。

我们必须在我的工作中这样做,代码量是非常重要的。我在这里深入研究这个主题是没有意义的。

潜在的C ++代码:

struct Quantity
{
   double value;
   std::string unit;
};

// Defines operations on Quantity.
Quantity operator+(Quantity const& q1, Quantity const& q2) { ... }
Quantity operator-(Quantity const& q1, Quantity const& q2) { ... }
Quantity operator*(Quantity const& q1, Quantity const& q2) { ... }
Quantity operator*(Quantity const& q1, double f) { ... }
Quantity operator/(Quantity const& q1, Quantity const& q2) { ... }
Quantity operator/(Quantity const& q1, double f) { ... }
Quantity convert(Quantity const& q, std::string const& unit) { ... }

auto L1 = Quantity(10, "m");
auto L2 = Quantity(10, "m");

auto a = L1*L2;  // Resulting in Quantity(100, "m^2")

auto F1 = Quantity(10, "N");
auto A1 = Quantity(2, "m^2");
auto p = F1/A1;  // Resulting in Quantity(5, "Pa")

auto A2 = Quantity(10, "deg");
auto A3 = Convert(A2, "rad");  // Resulting in Quantity(0.174533, "rad")

答案 4 :(得分:1)

嗯,你可能想用单位计算全程。

使用所有相关(SI?)基本单位执行类似的操作:

template <class T, int meter, int second, int pow_10, int pow_deginrad>
class unit {
    T num = 0;
};
// add convenience typedefs. Also look into `operator ""` for denoting literals.

现在你必须在一个地方定义类型和数量之间的算术 快乐的编码。