在C++ Core Guidlines P.1 change_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_speed
的参数,则会抛出错误。最后一行显示使用一些m
和s
文字定义的单位。这两个新功能都是现代C ++版本中的功能吗?如果是这样,将如何实现这种方式,以及需要什么版本的C ++?
答案 0 :(得分:13)
如评论中所述,核心准则中的示例使用用户定义的文字来构造可直观表示物理量的特定于应用程序的类型。为了说明特定示例,请考虑以下类型:
if (ZipFolder != null)
{
// Application now has read/write access to all contents in the picked folder (including other sub-folder contents)
StorageApplicationPermissions.FutureAccessList.AddOrReplace("PickedFolderToken", ZipFolder);
await Task.Run(() =>
{
try
{
ZipFile.CreateFromDirectory(ApplicationData.Current.LocalFolder.Path, $"{ZipFolder.Path}\\{Guid.NewGuid()}.zip");
Debug.WriteLine("folder zipped");
}
catch (Exception w)
{
Debug.WriteLine(w);
}
});
}
跟踪/* "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
实例而言则没有意义,但让我们在这里考虑最简单的示例。现在,让我们看两个用户定义的文字:
Speed
它们使您可以实例化#include <ratio>
auto operator ""_m(unsigned long long n)
{
return Length<>{n};
}
auto operator ""_km(unsigned long long n)
{
return Length<std::kilo>{n};
}
对象,如下所示:
Length
为了构造一个/* We use auto here, because the suffix is so crystal clear: */
const auto lengthInMeter = 23_m;
const auto lengthInKilometer = 23_km;
实例,让我们定义一个适当的运算符,将Speed
除以Length
:
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()};
}
但最重要的是,如何调用这样的函数:
void change_speed(const Speed& s)
{
/* Complicated stuff... */
}
正如注释中提到的@KillzoneKid一样,C ++ 11才能正常工作。
答案 1 :(得分:3)
您的代码涉及两件事:
使用强/单位类型使代码更健壮,即,您可以区分两种整数类型。这是某些语言(例如Ada)内置的,但不是C ++内置的,但是您可以创建包装整数类型的类来模仿这种行为(请参见下文)。
使用运算符文字以用户友好的方式创建此类的实例,即,您编写的是1s
而不是seconds{1}
。这只是一项便利功能,在某些地方可能会有用。
使用强整数类型非常有用,因为它使您的代码更容易出错 * :
seconds
和hours
)中,如果您失去精度,则不会进行隐式转换,例如,无法将seconds
转换为{{ 1}},除非您使用浮点类型(hours
/ float
)来表示我们。double
转换为hours
,而不必手动乘以3600。seconds
auto speed = 70km / 1h; // Don't bother deducing the type of speed, let the compiler do it for you.
,您知道这是什么,您不必希望记录该函数的人返回{{1} }提到这代表微秒... * 我在这里仅谈论隐式转换,当然,您可以显式进行转换,例如,使用microseconds
(精度损失)。
单位类型
“单元”类中的包装整数类型始终可用,但是C ++ 11带来了一种标准的包装整数类型:std::chrono::duration
。
可以通过以下方式定义“单元”类:
unsigned long long
,duration_cast
,... 当前,标准仅提供类似持续时间的类型,但是已经进行了讨论(也许是一项提案)来提供更通用的基本单位类型,例如:
int
...其中double
是占位符,指示所表示的事物的种类,例如:
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
模板参数是C ++类型:
template <class Rep, class Period = std::ratio<1>> class duration;
小时。 Rep
模板参数定义了double
类型与一秒(这是选择的基本持续时间)之间的比率:
std::ratio
是一种非常方便的标准定义类型,它简单地表示两个整数之间的比率,并具有相应的运算符(Period
,duration
,...)。*
,/
,... 运算符文字
这些已在C ++ 11中引入,并且为literals operators。
std::chrono::seconds
是标准的,并包含在chrono
标准库中:
std::chrono::minutes
s
不是标准的,因此应该以{{1}}为前缀(因为它是用户定义的),例如using namespace std::chrono_literals;
auto one_second = 1s;
auto one_hour = 1h;
。您可以这样定义自己的运算符:
m