您的代码中有两个不同的东西:
使用强/单位类型使您的代码更加健壮,即区分两种整数类型。这在某些语言(例如 Ada)中是内置的,但在 C++ 中没有,但您可以创建包装整数类型的类来模拟这种行为(见下文)。
使用操作符文字以用户友好的方式创建此类类的实例,即您编写1s而不是seconds{1}。这只是一个方便的功能,在某些地方可能很有用。
使用强整数类型非常有用,因为它使您的代码更不容易出错*:
- 您无法像在现实生活中那样在表示持续时间和长度的类型之间进行转换。
- 在表示同一种事物的类型中(例如,
seconds 和 hours),如果您失去精度,则没有隐式转换,例如,您不能将 seconds 转换为 hours,除非您代表我们的浮点类型 (float / double)。
- (隐式和非隐式)转换为您处理缩放:您可以将
hours 转换为 seconds,而无需手动乘以 3600。
- 您可以提供实际的运算符来为您处理转换,例如,在您的示例中,长度和持续时间之间的除法运算符可以提供速度。根据长度类型和持续时间类型自动推断出确切的速度类型:
auto speed = 70km / 1h; // Don't bother deducing the type of speed, let the compiler do it for you.
- 单位类型是自记录的:如果一个函数返回
microseconds,你知道这是什么,你不必希望记录返回unsigned long long的函数的人提到这个代表微秒...
* 这里只说隐式转换,当然你也可以显式地做转换,比如使用duration_cast(精度损失)。
单位类型
在“单元”类中包装整数类型一直可用,但 C++11 带来了一种标准的包装整数类型:std::chrono::duration。
“单元”类可以通过以下方式定义:
- 它所代表的事物类型:时间、长度、重量、速度……
- 用于表示这些数据的 C++ 类型:
int、double、...
- 此类型与同一单元的“1-type”之间的比率。
目前,标准只提供了类似持续时间的类型,但已经讨论过(可能是提议?)提供更通用的基本单元类型,例如:
template <class Unit, class Rep, class Ratio = std::ratio<1>> class unit;
...其中Unit 将是一个占位符,指示所代表的事物类型,例如:
struct length_t { };
template <class Rep, class Ratio = std::ratio<1>>
using length = unit<length_t, Rep, Ratio>;
但这还不是标准的,让我们看看std::chrono::duration:
template <class Rep, class Period = std::ratio<1>> class duration;
Rep 模板参数是 C++ 类型:
- 标准定义的持续时间类型具有整数表示(已定义实现)。
- 基础类型定义了可以隐式进行的转换类型:
- 您可以将整数小时隐式转换为整数秒(乘以 3600)。
- 您可以将整数秒隐式转换为整数小时,因为这样会丢失精度。
- 您可以将整数秒转换为
double 小时。
Period 模板参数定义了duration 类型与一秒(这是选择的基本持续时间)之间的比率:
-
std::ratio 是一种非常方便的标准定义类型,它简单地表示两个整数之间的比率,并带有相应的操作(*、/、...)。
- 标准提供多种不同比率的持续时间类型:
std::chrono::seconds、std::chrono::minutes、...
运算符字面量
这些是在 C++11 中引入的,是literals operators。
s 是标准的,包含在chrono 标准库中:
using namespace std::chrono_literals;
auto one_second = 1s;
auto one_hour = 1h;
m 不是标准的,因此应以_ 为前缀(因为它是用户定义的),例如23_m。您可以像这样定义自己的运算符:
constexpr auto operator "" _m(unsigned long long ull) {
return meters{ull};
}