【发布时间】:2020-06-26 07:43:53
【问题描述】:
自从学习了 Rust,我就成为了 newtype idiom 的粉丝,我收集了 Rust 借用的 from Haskell。
新类型是基于标准类型的独特类型,可确保函数参数的类型正确。
例如,下面的old_enough 函数必须传递一个以年为单位的年龄。它不会以 Days 为单位或作为普通 i64 编译。
struct Days(i64);
struct Years(i64);
fn old_enough(age: &Years) -> bool {
age.0 >= 18
}
这与 C++ 中的 typedef 或 using 声明不同,后者只是重命名类型。
例如,下面的 old_enough 函数将接受 int、Days 中的年龄或任何其他转换为 int 的内容:
typedef int Days;
using Years = int;
bool old_enough(Years age) {
return age >= 18;
}
由于上面的示例只使用整数,Reddit 上的this 帖子建议使用枚举类,例如:
enum class Days : int {};
enum class Years : int {};
bool old_enough(Years age) {
return static_cast<int>(age) >= 18;
}
或者它可以简单地使用结构,例如 Rust,例如:
struct Days final {int value;};
struct Years final {int value;};
bool old_enough(Years age) {
return age.value >= 18;
}
在C++ 中实现newtype 成语的最佳方法是什么?
有标准方法吗?
EDIT 问题Strongly typed using and typedef 类似。但是,它不考虑newtype 成语。
【问题讨论】:
-
在 C++ 中,您可能会创建一个
Year类,并在构造函数和/或赋值级别进行验证。像auto year = new Year(2002)然后year.old_enough(),或者对于更严格的实现,throw当提供无效值时。 -
如果你真的只需要相同的类型但作为不同的类型,不幸的是它需要相当多的样板。幸运的是已经有人写了,你可以使用
BOOST_STRONG_TYPEDEF,但总的来说我同意tad,Year不是int,应该有自己的类型 -
这能回答你的问题吗? Strongly typed using and typedef
-
@tadman 你的意思是
auto year = Year(2002); -
可能值得注意的是,对于这个特定的示例,C++ 标准库已经具有
std::chrono::years和std::chrono::days,它们本质上已经是这种类型的包装器。 (尽管在这种情况下,也可能存在从std::chrono::days到std::chrono::seconds的隐式转换,在幕后将值乘以正确的转换因子。)Boost 还有一个单位库,用于处理在 SI 中包装双精度值(或英制单位)并在幕后进行转换。