如何使用可能不同的boost :: dimension存储boost :: quantity

问题描述 投票:2回答:2

我正在使用boost::units库来强化科学项目中的物理一致性。我已阅读并尝试过boost文档中的几个示例。我可以创建我的尺寸,单位和数量。我做了一些微积分,效果很好。这正是我的预期,除了......

在我的项目中,我处理时间序列,它具有基于六个维度的几个不同单位(温度,浓度,密度等)。为了实现安全简便的单位转换,我想在每个通道类中添加一个成员来表示时间序列的维度和单位。而且,数据处理(导入,转换等)是用户驱动的,因此是动态的。

我的问题如下,因为boost::units结构,均匀系统内但具有不同尺寸的数量具有不同的类型。因此,您无法直接声明成员,例如:

boost::units::quantity channelUnits;

编译器将声称您必须使用模板V形符号指定尺寸。但是,如果这样做,您将无法存储不同类型的数量(例如具有不同尺寸的数量)。

然后,我查找了boost::units::quantity声明,以找出是否有一个我可以以多态方式使用的基类。但我没有找到它,相反我发现boost::units大量使用模板元编程,这不是一个问题,但不完全符合我的动态需求,因为一切都是在编译时解决而不是在运行时。

在更多阅读之后,我尝试在boost::variant对象中包装不同的数量(很高兴第一次见到它)。

typedef boost::variant<
   boost::units::quantity<dim1>,
   ...
> channelUnitsType;
channelUnitsType channelUnits;

我进行了一些测试,似乎有效。但我对boost::variant和访客模式没有信心。

我的问题如下:

  • 有另一种 - 也许是最好的 - 有运行时类型解析的方法吗?
  • dynamic_cast是其中之一吗?单位转换不会经常发生,只有少数数据受到关注。
  • 如果boost::variant是一个合适的解决方案,它的缺点是什么?
c++ physics boost-units
2个回答
2
投票

我一直在考虑这个问题并得出以下结论:

1.实现类型擦除(优点:好的接口,缺点:内存开销)

看起来不可能存储没有通用维度的一般数量的开销,这破坏了库的设计原则之一。即使是类型擦除也无济于事。

2.实现可转换类型(优点:好的接口,缺点:操作开销)

我看到的没有存储开销的唯一方法是选择一个传统的(可能是隐藏的)系统,其中所有单元都被转换为。没有内存开销,但几乎所有对值的查询都存在乘法开销,并且有大量的转换和一些高指数的精度,(考虑从avogadro数转换为10次幂)。

3.允许隐式转换(优点:好的接口,缺点:难以调试,意外的操作开销)

另一个选项,主要是在实际方面来缓解问题是允许在接口级别进行隐式转换,请参见此处:https://groups.google.com/d/msg/boost-devel-archive/JvA5W9OETt8/5fMwXWuCdDsJ

4.模板/通用代码(优点:没有运行时或内存开销,概念上正确,哲学遵循库的原理,缺点:难以调试,丑陋的接口,可能的代码膨胀,到处都有很多模板参数)

如果您询问图书馆设计师,他们可能会告诉您需要使您的功能通用。这是可能的,但它使代码复杂化。例如:

template<class Length>
auto square(Length l) -> decltype(l*l){return l*l;}

我使用C ++ 11来简化这里的示例(可以在C++98中完成),并且还表明这在C ++ 11中变得更容易(在C ++ 14中使用decltype(auto)更简单。

我知道这不是你想到的代码类型,但它与库的设计是一致的。您可能会想,我如何将此功能限制为物理长度而不是其他内容?嗯,答案是你不需要这个,但如果你坚持,在最坏的情况下......

template<class Length, typename std::enable_if<std::is_same<typename get_dimension<Lenght>::type, boost::units::length_dimension>::value>::type>
auto square(Length l) -> decltype(l*l){return l*l;}

(在更好的情况下,decltype将完成SFINAE工作。)

在我看来,选项4和可能与3.结合是最优雅的方式。


参考文献:

https://www.boost.org/doc/libs/1_69_0/boost/units/get_dimension.hpp


3
投票

更深入地解决我的问题,我读了两篇提供解决方案的文章:

  • Kostadin Damevski,表达科学组件软件接口中的测量单位;
  • 江凌孝,一种验证C程序维度单位正确性的实用型系统。

第一个给出了接口实现的好主意。第二部分概述了您必须应对的内容。

我记住,boost::units是编译时维度一致性的完整而有效的方法,在运行时没有开销。无论如何,对于涉及尺寸变化的运行时尺寸一致性,您需要一个boost::units不提供的动态结构。所以我就是这样:设计一个完全符合我需求的单元类。要做更多的工作,最终会更满意......

关于原始问题:

  • boost::variant工作得很好(它提供了动态的boost::units缺失)。此外,它可以开箱即用。因此,这是一种有效的方法。但是它为一个简单的方法添加了一层抽象 - 我不是说琐碎的 - 可以由一个类完成的任务。
  • 铸造是通过boost::variant_cast<>而不是dynamic_cast<>实现的。
  • boost::any可能更容易实现,但序列化变得很难。
© www.soinside.com 2019 - 2024. All rights reserved.