所以,我正在努力理解C++中的整个CRTP问题.我在网上找到的关于你为什么应该在意使用它的理由有几个(1) (2),那就是它允许以半自动的方式向你的代码添加功能.我的意思是,我可以让编译器为我演绎一些功能,只要求我实现几个小功能.

例如,我可能想要形式化一个Comparable"特征"(使用Rust单词),迫使用户提供<==的实现,并仅使用这两个来推断所有其他比较.IIRC,这是当您实例化自定义类的std::set时发生的情况(编译器要求您提供operator<()实现).

因此,我对C++的CRTP有两个问题:

  1. 从这个意义上说,"trait "这个词的用法合适吗?我可以更进一步地说抽象数据类型吗?CRTP是实现这一点的C++习惯用法吗(请原谅C++纯粹主义者)?因为在我看来它们非常相似:您定义了一些基本实现,并遵循一些演绎规则,您可以获得其他行为/功能
  2. 我可以通过使用抽象类来获得相同的东西(类似于特征的东西)吗?如果是这样,为什么我要使用CRTP呢?

谢谢!


EDIT:在 comments 中我被告知,在C++中,"特征"一词指的是一个特定的concept,这与例如在Rust中使用的不同.因此,我稍微改变/澄清了我的问题:CRTP类似于Rust's个特征(IIUC,特别是#[derive]d特征)吗?

推荐答案

CRTP习惯用法是一种将泛型功能注入类的工具,特别是通过在类中插入成员来实现的.这类事情的通用、语言中立的术语是"mixin".从机械上讲,"混合"通常指的是使用基类将成员注入类without的方法.因为CRTP使用基类,所以它不严格符合Mixin的定义.但这是一个机制问题,而不是概念问题;即使不是通过通常的方法,CRTP基类也可以实现Mixin的一般功能.

铁 rust 的特征也有点像混合粉.但由于一个非常重要的原因,CRTP不像是 rust 病的特征.铁 rust 特征的全部意义在于,接收端的职业不一定要被赋予一种特征.在Rust中,您可以强制一个类型具有一个特征接口,而该类型甚至不知道特征的存在.

CRTP不能这样做.类必须 Select 加入基于CRTP的Mixin接口.

所以不,我不会把CRTP称为铁 rust 特征.事实上,您发现的被称为"特征"的C++概念更像是铁 rust 特征.C++特征定义了一个任何类型都可以采用的界面,通过模板专门化,用户可以将其正常界面适配到特征界面.相同的 idea ,只是通过不同的机制.

这种名义上的相似并不是巧合:Rust的制造者认识到了C++特征习语的实用性,并专门构建了一个语言功能来促进它(从而避开了在C++中使用基于特征的接口所产生的所有问题).

Rust相关问答推荐

有条件默认实现

常量泛型和类型枚举箱有重叠的用途吗?

文档示例需要导入相关的 struct ,但仅在运行测试时.这是故意的行为吗?

在使用#[NO_STD]时,如何在Rust中收到紧急消息?

替换可变引用中的字符串会泄漏内存吗?

为什么我们需要std::thread::scope,如果我们可以使用thread.join()在函数的生命周期内删除引用?

避免在Collect()上进行涡鱼类型的涂抹,以产生<;Vec<;_>;,_>;

为什么TcpListener的文件描述符和生成的TcpStream不同?

期望一个具有固定大小 x 元素的数组,找到一个具有 y 元素的数组

为什么 js_sys Promise::new 需要 FnMut?

为什么我可以使用 &mut (**ref) 创建两个实时 &mut 到同一个变量?

Button.set_hexpand(false) 不会阻止按钮展开

当锁被释放时,将锁包装到作用域中是否会发生变化?

将 Futures 的生命周期特征绑定到 fn 参数

从现有系列和 map 值创建新系列

以下打印数组每个元素的 Rust 代码有什么问题?

将数据序列化为 struct 模型,其中两个字段的数据是根据 struct 中的其他字段计算的

为什么-x试图解析为文字并在声明性宏中失败?

BigUint 二进制补码

如何构建包含本地依赖项的 docker 镜像?