C++ C+中类型的单位+;

C++ C+中类型的单位+;,c++,cpp-core-guidelines,C++,Cpp Core Guidelines,在p.1change\u speed示例中,它显示了一种speed类型,如下所示: change_speed(Speed s); // better: the meaning of s is specified // ... change_speed(2.3); // error: no unit change_speed(23m / 10s); // meters per second 我对这个例子的最后两行特别感兴趣。第一个似乎表明,如果您没有提供带有change\u speed参数的单元

在p.1
change\u speed
示例中,它显示了一种
speed
类型,如下所示:

change_speed(Speed s); // better: the meaning of s is specified
// ...
change_speed(2.3); // error: no unit
change_speed(23m / 10s); // meters per second

我对这个例子的最后两行特别感兴趣。第一个似乎表明,如果您没有提供带有
change\u speed
参数的单元,它将抛出一个错误。最后一行显示使用
m
s
文字定义的单位。这两种新特征在C++的现代版本中都有吗?如果是这样的话,那么如何实现这种情况,以及需要什么样的C++版本?如注释中提到的

< P>,核心指南的示例使用用户定义的文字来构造直观直观地表示物理量的应用程序特定类型。为了说明他们的具体例子,考虑这些类型:

/* "Strong" speed type, unit is always [m/s]. */
struct Speed {
   long double value;
};

/* "Strong" length type, parameterized by a unit as multiples of [m]. */    
template <class Period = std::ratio<1>> struct Length {
   unsigned long long value;
};
它们允许您实例化
Length
对象,如下所示:

/* We use auto here, because the suffix is so crystal clear: */
const auto lengthInMeter = 23_m;
const auto lengthInKilometer = 23_km;
为了共同构造一个
速度
实例,让我们定义一个合适的运算符,将
长度
除以
持续时间

#include <chrono>

template <class LengthRatio, class Rep, class DurationRatio>
auto operator / (const Length<LengthRatio>& lhs,
      const std::chrono::duration<Rep, DurationRatio>& rhs)
{
   const auto lengthFactor = static_cast<double>(LengthRatio::num)/LengthRatio::den;
   const auto rhsInSeconds = std::chrono::duration_cast<std::chrono::seconds>(rhs);

   return Speed{lengthFactor*lhs.value/rhsInSeconds.count()};
}
template <class Rep, class Period = std::ratio<1>> class duration;
但最重要的是,如何调用此函数:

using namespace std::chrono_literals;

int main(int, char **)
{
   change_speed(23_m/1s);
   change_speed(42_km/3600s);
   change_speed(42_km/1h);

   return 0;
}

正如@KillzoneKid在评论中提到的,这需要C++11才能工作。

代码中涉及两个不同的方面:

  • 使用强/单位类型使代码更加健壮,即区分两种整数类型。这是在一些语言(例如艾达)中内置的,但不是C++中的,但是您可以创建封装整数类型来模仿这种行为的类(参见下面)。
  • 使用运算符文字以用户友好的方式创建此类类的实例,即您编写
    1s
    而不是
    seconds{1}
    。这只是一个方便的特性,在某些地方可能很有用

  • 使用强整数类型非常有用,因为它使代码更不容易出错*:

    • 在现实生活中,不能在表示持续时间和长度的类型之间进行转换
    • 在表示同类事物的类型中(例如,
      seconds
      hours
      ),如果精度降低,则不会有隐式转换,例如,除非您使用浮点类型(
      float
      /
      double
      )表示我们的时间,否则无法将
      seconds
      转换为
      hours
    • (隐式和非隐式)转换为您提供缩放功能:您可以将
      小时
      转换为
      ,而无需手动乘以3600
    • 您可以提供实际的运算符来为您处理转换,例如,在您的示例中,长度和持续时间之间有一个除法运算符,可以提供速度。根据长度类型和持续时间类型自动推断出准确的速度类型:
    • 单元类型是自记录的:如果函数返回
      微秒
      ,你知道这是什么,你不必希望记录函数返回
      无符号长
      的家伙提到这代表微秒
    *这里我只讨论隐式转换,当然,您可以显式地进行转换,例如,使用
    持续时间\u cast
    (精度损失)


    单位类型

    在“unit”类中包装整数类型始终可用,但C++11带来了一个标准的包装整数类型:

    “单位”类可通过以下方式定义:

    • 它所代表的事物类型:时间、长度、重量、速度
    • 它用来表示这些数据的C++类型:<代码> int <代码>,<代码>双< /代码>,…< /LI>
    • 此类型与同一装置的“1型”之间的比率
    目前,标准仅提供了类似持续时间的类型,但已经讨论过(可能是提案?)提供更通用的基本单元类型,例如:

    template <class Unit, class Rep, class Ratio = std::ratio<1>> class unit;
    
    但这还不是标准的,所以让我们看看
    std::chrono::duration

    #include <chrono>
    
    template <class LengthRatio, class Rep, class DurationRatio>
    auto operator / (const Length<LengthRatio>& lhs,
          const std::chrono::duration<Rep, DurationRatio>& rhs)
    {
       const auto lengthFactor = static_cast<double>(LengthRatio::num)/LengthRatio::den;
       const auto rhsInSeconds = std::chrono::duration_cast<std::chrono::seconds>(rhs);
    
       return Speed{lengthFactor*lhs.value/rhsInSeconds.count()};
    }
    
    template <class Rep, class Period = std::ratio<1>> class duration;
    
    m
    一个不是标准的,因此应该加上前缀
    (因为它是用户定义的),比如
    23\u m
    。您可以这样定义自己的运算符:

    constexpr auto operator "" _m(unsigned long long ull) { 
        return meters{ull};
    }
    

    也许这就是你的意思:它不会出错,它不会编译,因为<代码> CuxEySuth[/COD]是速度而不是浮点文字。一旦我们有C++的单元,我们就知道如何进行良好的量纲分析,以及如何用无量纲方程计算模拟是一个很好的解决方案!!)OLIV在C++中实现单元已经非常容易,特别是如果你简单地包装一个<代码> STD::Simo::持续时间< />代码>。这缺少维度(Units模板参数)的概念,也不可能用不同维度乘/除数字:1米/1秒=1米/1秒=>dimensionaly米/2=速度。参见增压装置。
    template <class Rep, class Period = std::ratio<1>> class duration;
    
    using namespace std::chrono_literals;
    auto one_second = 1s;
    auto one_hour = 1h;
    
    constexpr auto operator "" _m(unsigned long long ull) { 
        return meters{ull};
    }