在 Rust 编程语言中,您可以声明一个带有必须实现特征的泛型类型参数的函数。 (不知道的人可以认为
implement
是inheritance
,trait
是class
)。因此,传递给该函数的对象必须实现该特征。例如:
// Define a function `printer` that takes a generic type `T` which
// must implement trait `Display`.
fn printer<T: Display>(t: T) {
println!("{}", t);
}
现在我的问题是,如何在 C++ 中定义这样的模板函数来强制类型继承一些基类?
std::is_base_of
来检查类型是否具有特定的基类。利用 SFINAE 看起来像:
template <typename T, std::enable_if_t<std::is_base_of_v<BASE_CLASS, T>, bool> = true>
ret_type function_name(T t)
{
// your code
}
仅当
T
派生自 BASE_CLASS
或者是相同类型时,上述模板才会被实例化。
在 C++20 中,您可以使用
requires
来简化这一过程。
由于在撰写本文时 C++20 尚未广泛普及,因此这里有一个向后兼容的示例:
template<typename T>
std::enable_if_t<std::is_base_of_v<Display, T>> fn(const T& t)
{
// your favorite println implementation over t
}
如果您想返回一个值,请使用
std::enable_if_t<condition, return_type>
。
C++20 方式:
template <std::derived_from<Display> T>
void printer(const T &value)
{
// ...
}
或者缩写模板语法:
void printer(const std::derived_from<Display> auto &value)
{
// ...
}
请注意,
std::derived_from
和std::is_base_of_v
之间存在一些区别(除了其中一个是概念):后者检查任何基础,而前者检查明确的公共基础。如果这就是您想要的,但您没有 C++20,您可以额外检查 std::is_convertible_v<A *, B *>
。