这是奇怪重复出现的模板模式,简称 CRTP。这种技术的一个主要优点是它启用了所谓的静态多态性,这意味着函数 intorch::data::datasets::Dataset
可以调用 的函数CustomDataset
,而无需使这些函数虚拟化(从而处理虚拟方法调度的运行时混乱等)。enable_if
您还可以根据自定义数据集类型的属性执行编译时元编程,例如 compile-time s。
在 PyTorch 的情况下,BaseDataset
(的超类Dataset
)大量使用这种技术来支持诸如映射和过滤之类的操作:
template <typename TransformType>
MapDataset<Self, TransformType> map(TransformType transform) & {
return datasets::map(static_cast<Self&>(*this), std::move(transform));
}
注意派生类型的静态this
转换(只要正确应用 CRTP 就合法);datasets::map
构造一个MapDataset
对象,该对象也由数据集类型参数化,允许MapDataset
实现静态调用方法,例如(或者如果它们不存在,则会get_batch
遇到编译时错误)。
此外,由于MapDataset
接收自定义数据集类型作为类型参数,编译时元编程是可能的:
/// The implementation of `get_batch()` for the stateless case, which simply
/// applies the transform to the output of `get_batch()` from the dataset.
template <
typename D = SourceDataset,
typename = torch::disable_if_t<D::is_stateful>>
OutputBatchType get_batch_impl(BatchRequestType indices) {
return transform_.apply_batch(dataset_.get_batch(std::move(indices)));
}
/// The implementation of `get_batch()` for the stateful case. Here, we follow
/// the semantics of `Optional.map()` in many functional languages, which
/// applies a transformation to the optional's content when the optional
/// contains a value, and returns a new optional (of a different type) if the
/// original optional returned by `get_batch()` was empty.
template <typename D = SourceDataset>
torch::enable_if_t<D::is_stateful, OutputBatchType> get_batch_impl(
BatchRequestType indices) {
if (auto batch = dataset_.get_batch(std::move(indices))) {
return transform_.apply_batch(std::move(*batch));
}
return nullopt;
}
请注意,条件启用依赖于SourceDataset
,我们只能使用它,因为数据集是使用此 CRTP 模式参数化的。