c++ - 原始类型的强别名
问题描述
我正在阅读这个https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#S-philosophy并且在 P1 中有这个
change_speed(double s); // bad: what does s signify?
// ...
change_speed(2.3);
A better approach is to be explicit about the meaning of the double (new speed or delta on old speed?) and the unit used:
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
这让我想知道(因为我非常喜欢这个想法)如何实现“速度”类型。
我试过这个
using Speed = double;
void change_speed(Speed s)
{
cout << s;
}
但这还不够强大,因为我仍然可以做到
double j = 43.0;
change_speed(j);
和
change_speed(42.0);
注意:如果速度类型可以按照我的意愿工作,那么最后一个仍然需要,但必须是一个演员:-
change_speed(static_cast<Speed>(42.0));
因此,我尝试为它创建一个单字段结构(稍后将被模板化)。但我意识到我需要每一个运算符重载(可能还有一些甚至不存在的运算符),这似乎太多了。
那么,有没有办法做到这一点?
解决方案
您必须使用所需的转换行为和运算符创建一个新类。但是,有一些库可以帮助简化该过程。例如,键入安全
对于整数类型,您还可以在 C++17 中使用空枚举。例如,
enum class Strong : int {};
void func(Strong);
int main() {
// func(15); doesnt compile
func(Strong{15});
func(static_cast<Strong>(15));
auto s = Strong{15};
int x = static_cast<int>(s);
}
编辑:
详细地说,可以在强类型中设计不同的功能,因此解决方案最终取决于您想要的确切行为。如果您正在寻找创建强类型的快捷方式或构建块,type_safe 是我见过的最好的东西,也许您可以查看实现的想法。
我将在一个示例案例中分享我的想法,我们希望创建一个Strong
类似于int
.
一个关键的选择是构造,或从基础类型转换。基本上,选择是在显式或隐式构造函数之间,即explicit Strong(int)
或Strong(int)
。如果您想要change_speed(42.0);
构建类似的东西,请使用隐式,如果您想要求change_speed(static_cast<Speed>(42.0));
显式。
然后,您可以进一步指定要如何转换回基础类型。如果您想要求使用静态转换(例如explicit operator int()
),则可能是显式转换运算符,或者如果您可以使用隐式转换(例如),则可能是隐式转换运算符operator int()
。也许您根本不想使用转换运算符,而您宁愿提供一个免费的函数来访问底层类型(例如int underlying(Strong const&)
)。如果您希望能够编写,auto x = Strong{}; int y = x;
那么您需要一个隐式转换运算符。如果不是,请使用显式运算符或自由函数。
对于运算符,您当然可以选择将哪些添加到强类型中,对于二元运算符,您可以选择是否提供不对称运算符(例如,可以Strong
和int
被添加在一起吗?)。当然,这个选择会与您之前的选择相互作用。如果您允许从底层类型进行隐式转换,那么对称运算符将已经支持非对称操作。例如Strong operator+(Strong, Strong)
,如果一个参数int
只要int
您的定义中有一个隐式构造函数,就会编译Strong
。
简而言之,它确实取决于你想要什么。但希望这能让您更好地了解一些可用的选择及其产生的影响。
如果我们谈论的是完整的单位系统(米、公斤等),还有更多要讨论的内容。为此,您可以查看Boost.Units的想法。
推荐阅读
- laravel - Laravel Test 失败时不执行 tearDown 方法
- python - Etsy API ListingVariationImage 端点期望 value_id 与已知 value_id 不同
- c# - C# 动态加载程序集并使用它然后卸载它
- javascript - 在嵌套的 Promise 中调用 resolve 之前执行的 Promise then()
- python - \x00 在 .txt 文件的开头
- arrays - 在数组中查找最大元素 - 程序无法识别最后一个元素
- javascript - 如果在谷歌地图的搜索框中复制粘贴地址,位置不会改变
- biztalk - 设置段的默认值
- django - 如何在 django 中使用 only() 方法
- sql - aws athena SQL 查询;为每个唯一的 column1 获取 column2 的唯一计数