【问题标题】:Physical Boost.Units User Defined LiteralsPhysical Boost.Units 用户定义文字
【发布时间】:2012-02-13 09:03:59
【问题描述】:

现在我们很快就有了用户定义文字 (UDL),例如在 GCC 4.7 中,我急切地等待(物理)单元库(例如 Boost.Units)使用它们来缓解文字的表达式,例如 1+3i3m3meter13_meter。是否有人使用支持这种行为的 UDL 为 Boost.Units 编写了扩展?

【问题讨论】:

  • 考虑到唯一支持 UDL 的编译器是 GCC,即使这样也只是在不稳定的版本中,我猜不是。此外,不以_ 开头的UDL 保留用于未来的标准;你不能自己写。
  • 很高兴知道!我只是想知道 UDL 如何与当前的数字文字后缀 lfd 发生冲突。 _ 要求回答了这个问题。

标签: c++ user-defined-literals boost-units


【解决方案1】:

没有人提出过这样的扩展。只有 gcc(可能还有 IBM?)有 UDL,所以可能需要一段时间。我希望某种单位能够进入现在开始的 tr2。如果发生这种情况,我相信单位的 UDL 会出现。

这行得通:

//  ./bin/bin/g++ -std=c++0x -o units4 units4.cpp

#include <boost/units/unit.hpp>
#include <boost/units/quantity.hpp>
#include <boost/units/systems/si.hpp>

using namespace boost::units;
using namespace boost::units::si;

quantity<length, long double>
operator"" _m(long double x)
{ return x * meters; }

quantity<si::time, long double>
operator"" _s(long double x)
{ return x * seconds; }

int
main()
{
  auto l = 66.6_m;
  auto v = 2.5_m / 6.6_s;
  std::cout << "l = " << l << std::endl;
  std::cout << "v = " << v << std::endl;
}

我认为浏览你最喜欢的单位并做到这一点并不难。

关于将它们放入库中: 文字运算符是命名空间范围函数。后缀的竞争将变得丑陋。我会(如果我被提升的话)有

namespace literals
{
...
}

那么Boost用户就可以做到了

using boost::units::literals;

以及您通常使用的所有其他使用 decl。例如,您将不会被std::tr2::units 重创。同样,如果您自己滚动。

【讨论】:

  • 烦恼#1:文字运算符只能采用少数参数类型。拥有返回 float 和 double 以及 long double 的版本会很好,因此计算不会一直提升为 long double 吗? ADL 不会仅按返回类型进行选择 - 精度特定的命名空间和使用?呃。
  • 烦恼#2:除了所有的单位,最好至少有公倍数。例如不仅仅是“m”,还有“km”、“cm”、“mm”表示长度,“Hz”、“kHz”、“MHz”、“GHz”表示频率。它可能会变得乏味 - 或涉及一些宏。
  • 有些应用程序的大小是一个约束。矩阵数学可以属于这一类。 OTOH,将文字转换为您喜欢的大小或为不同的返回类型使用不同的后缀并不难 - f_km 表示浮动公里。最后,文字往往不会支配代码——它们通常很少。只要对矩阵等大型对象的操作不会将中间变量提升到无法管理的大小,就可以了。我想这些烦恼没什么大不了的。
  • 我承认在一些(很多)情况下,提升到更高的精度至少是可以的并且可能是有益的。
  • 我已经为 S.I. 单位的升压单位实现了一组简单的用户定义文字,包括所有 S.I. 前缀 here
【解决方案2】:

在我看来,为 Boost.Units 使用字面量并没有太大的好处,因为使用现有功能仍然可以实现更强大的语法。

在简单的情况下,看起来像文字是要走的路,但很快你就会发现它不是很强大。 例如,您仍然需要为组合单位定义字面量,例如,如何表示 1 m/s(一米每秒)?

目前:

auto v = 1*si::meter/si::second; // yes, it is long

但是使用文字?

// fake code
using namespace boost::units::literals;
auto v = 1._m_over_s; // or 1._m/si::second; or 1._m/1_s // even worst

可以利用现有功能实现更好的解决方案。这就是我所做的:

namespace boost{namespace units{namespace si{ //excuse me!
namespace abbreviations{
    static const length             m   = si::meter;
    static const time               s   = si::second;

    // ...
}
}}} // thank you!

using namespace si::abbreviations;
auto v = 1.*m/s;

您可以使用相同的方式:auto a = 1.*m/pow&lt;2&gt;(s); 或根据需要扩展缩写(例如 static const area m2 = pow&lt;2&gt;(si::meter);

你还想要什么?

也许组合解决方案可能是这样的方式

auto v = 1._m/s; // _m is literal, /s is from si::abbreviation combined with operator/

但是会有这么多的冗余代码,收益微乎其微(在数字后面用_替换*。)

我的解决方案的一个缺点是它使用常见的一个字母名称来污染命名空间。但除了在1.*m_/s_ 中添加下划线(在缩写的开头或结尾)之外,我没有看到解决方法,但至少我可以构建真正的单位表达式。

【讨论】:

    猜你喜欢
    • 2013-10-10
    • 1970-01-01
    • 2012-10-18
    • 1970-01-01
    • 1970-01-01
    • 2013-10-25
    • 1970-01-01
    • 1970-01-01
    • 2011-07-19
    相关资源
    最近更新 更多