58

在 C++ 中将物理单元定义为单独的类型并定义这些类型之间的有效操作是否有意义?

引入大量类型和大量运算符重载而不是仅使用普通浮点值来表示它们有什么好处吗?

例子:

class Time{...};
class Length{...};
class Speed{...};
...
Time operator""_s(long double val){...}
Length operator""_m(long double val){...}
...
Speed operator/(const Length&, const Time&){...}

哪里Time,LengthSpeed只能作为来自不同运算符的返回类型创建?

4

10 回答 10

55

在 C++ 中将物理单元定义为单独的类型并定义这些类型之间的有效操作是否有意义?

绝对地。标准 Chrono 库已经针对时间点和持续时间执行此操作。

引入大量类型和大量运算符重载而不是仅使用普通浮点值来表示它们有什么好处吗?

是的:您可以使用类型系统来捕获错误,例如在编译时将质量添加到距离,而不会增加任何运行时开销。

如果你不想自己定义类型和操作符,Boost 有一个Units 库可以解决这个问题。

于 2013-11-11T16:17:41.477 回答
21

我真的会为此推荐boost::units。它会在编译时完成所有转换,如果您尝试使用错误尺寸的伪代码示例,它还会为您提供编译时错误:

length l1, l2, l3;
area a1 = l1 * l2; // Compiles
area a2 = l1 * l2 * l3; // Compile time error, an area can't be the product of three lengths.
volume v1 = l1 * l2 * l3; // Compiles
于 2013-11-11T16:41:41.800 回答
13

我已经走上了这条路。优点都是类型安全的正常众多和良好的优点。我遇到的缺点:

  • 您需要在计算中节省中间值......例如秒平方。让这些值成为一种类型有点毫无意义(seconds^2 显然不是这样的类型velocity)。
  • 您将希望进行越来越复杂的计算,这将需要越来越多的重载/运算符定义来实现。

归根结底,对于简单的计算和简单的目的来说,它非常干净。但是当数学变得复杂时,很难让一个类型化的单位系统发挥得很好。

于 2013-11-11T16:24:12.057 回答
10

每个人都提到了类型安全保证作为一个优点。另一个巨大的优势是能够从单位(米)中抽象出概念(长度)。

例如,处理单位时的一个常见问题是将 SI 与公制混合使用。当概念被抽象为类时,这不再是问题:

Length width = Length::fromMeters(2.0);
Length height = Length::fromFeet(6.5);
Area area = width * height; //Area is computed correctly!
cout << "The total area is " << area.toInches() << " inches squared.";

类的用户不需要知道内部表示使用什么单位……至少,只要不存在严重的舍入问题。


我真的希望更多的三角函数库用角度来做这件事,因为我总是要查找它们是期望度数还是弧度......

于 2013-11-11T21:34:02.087 回答
4

对于那些正在寻找强大的编译时类型安全单元库,但对拖入 boost 依赖项犹豫不决的人,请查看units。该库被实现为一个没有依赖关系的单个 .h 文件,并带有一个用于构建单元测试/文档的项目。它使用 msvc2013、2015 和 gcc-4.9.2 进行了测试,并且应该也可以与这些编译器的更高版本一起使用。

完全披露:我是图书馆的作者

于 2016-02-09T12:52:42.470 回答
1

是的,这是有道理的。不仅在物理学中,而且在任何学科中。在金融领域,例如利率以反时间间隔为单位(通常表示为每年)。货币有许多不同的单位。它们之间的转换只能通过交叉汇率完成,具有一种货币除以另一种货币的维度。利息支付、股息支付、本金支付等通常以一定频率发生。

它可以防止将两个值相乘并以非法值结束。它可以防止汇总美元和欧元等。

于 2013-11-12T23:23:41.280 回答
1

我并不是说你这样做是错误的,但我们在我正在从事的项目中已经过火了,坦率地说,我怀疑它的好处超过了它的麻烦。特别是如果您在一个团队中,良好的变量命名(只是拼出该死的东西)、代码审查和单元测试将防止任何问题。另一方面,如果您可以使用 Boost,则可能需要检查单位(我没有)。

于 2013-11-14T16:05:12.413 回答
1

我在 Boost.Units 库的 CPPcon 2015 上做了一个教程演示。这是一个强大的库,每个科学应用程序都应该使用它。但是由于文档不足,很难使用。希望我的教程对此有所帮助。您可以在此处找到幻灯片/代码

于 2015-10-10T21:02:53.723 回答
1

要检查类型安全,您可以使用专用库。

最常用的是 boost::units,它工作得很好,没有执行时间开销,还有很多特性。如果这个库理论上可以解决您的问题。从更实际的角度来看,界面是如此尴尬且记录不充分,以至于您可能会遇到问题。而且编译时间随着维数的增加而急剧增加,所以在使用之前,请清楚地检查您是否可以在合理的时间内编译一个大型项目。

文档: http: //www.boost.org/doc/libs/1_56_0/doc/html/boost_units.html

另一种方法是使用 unit_lite。与 boost 库相比,功能较少,但编译速度更快,界面更简单,错误消息可读。这个库需要 C++11。

代码:https ://github.com/pierreblavy2/unit_lite

文档的链接在 github 描述中(我不允许在这里发布超过 2 个链接!!!)。

于 2015-09-15T16:37:06.103 回答
0

如果你想使用基于 c++20 的非常轻量级的仅头文件库,可以使用TU(Typesafe Units)。它支持所有 SI 单位的操作(*、/、+、-、sqrt、对任意浮点数的 pow、对标量单位的一元运算)。它支持具有浮点尺寸的单位,例如 length^(d) ,其中 d 是十进制数。此外,定义自己的单位也很简单。它还带有一个测试套件...

...是的,我是这个库的作者。

于 2022-02-05T09:47:05.877 回答