相当于 C++ 中的 `<T extends MyClass>`

vir*_*ual 4 c++ templates

在 Java 中,你可以定义一个泛型类型,它应该从另一个中插入,通过 <T extends MyClass> void myMethod(T item)

cpp中是否有等价物?我试过template<class T : Draw_Shape> class MyClass,但不工作。

Yak*_*ont 12

阅读以下内容时,请注意我不是Java 程序员。我对 Java 的了解几乎完全是抽象的,而且可能已经过时。因此,如果 Java 在上一两个版本中实现了泛型的具体化,我不知道。


因此,Java 泛型和 C++ 模板共享一些通用的语法和用法,但它们在底层是非常不同的。

Java泛型是围绕单个核心类型自动编写的强制转换和编译时类型检查的包装器。

另一方面,C++ 模板为每组模板参数生成新的不相关类型。

extends MyClassJava 中的语法有两件事。首先,它允许泛型的“核心”类型知道它T不仅是一个对象,而且实际上是某个接口的子类。这是“核心”类型安全使用方法所必需的(没有 can-fail-at-runtime 动态转换)。

在 C++ 中,这不会发生,因为模板实例化没有生成“核心”类型。每个模板实例都是独立编译的,因此知道操作是否有效。

它做的第二件事是,当错误的类型传递给泛型时,它会给出类型错误。它所做的第三件事是它允许 Java 在实例化之前检查通用代码的有效性。

其次,C++ 可以使用概念(如果你的编译器足够新)或使用一种称为 SFINAE 的技术,它同样强大,但在语法上很糟糕,老实说,它解决这个问题的能力是语言开发的一个意外(这是偶然的图灵完全的)。

对于第三个 C++ 中的检查模板,它已被多次提出,但一直遇到编译时性能问题。所以除了实例化模板之外,没有办法在 C++ 中做到这一点。

解决方案:

没做什么:

不,认真的。拥抱鸭子类型并且不限制模板参数。唯一的大缺点是丑陋的错误消息,并且很少出现“同名操作具有不同含义”。

static_assert

template<class T> class MyClass{
  static_assert(std::is_base_of_v<Draw_Shape,T>);
};
Run Code Online (Sandbox Code Playgroud)

这会生成干净的错误消息。有一些缺点是其他代码无法测试是否MyClass<X>是没有硬编译器错误的有效实例。

SFINAE:

template<class T,
  std::enable_if_t<std::is_base_of_v<Draw_Shape,T>, bool> =true
>
class MyClass{
};
Run Code Online (Sandbox Code Playgroud)

注意,=true没有测试比较值true。不是==true。这里发生的事情非常复杂和烦人。为此目的使用 SFINAE 是一种黑客行为,这只是一种让猴子看起来干净的猴子做的方法。

概念:

template<class T> requires std::is_base_of_v<Draw_Shape,T>
class MyClass{
};
Run Code Online (Sandbox Code Playgroud)

或者

template<std::is_derived_from<Draw_Shape> T>
class MyClass{
};
Run Code Online (Sandbox Code Playgroud)

请注意,概念需要现代 C++ 编译器和 std 库。