【发布时间】:2021-08-29 17:31:26
【问题描述】:
我有一段 C# 代码如下:
class Foo<T> where T : TClass
{
// body
}
有什么标准方法可以在 C++ 中实现泛型类型约束
【问题讨论】:
我有一段 C# 代码如下:
class Foo<T> where T : TClass
{
// body
}
有什么标准方法可以在 C++ 中实现泛型类型约束
【问题讨论】:
C++ 有std::is_base_of,可与 SFINAE(C++17 及更早版本)或需求 (C++20) 一起使用。 C++20还增加了std::derived_from的概念。
C++17:
#include <type_traits>
#include <cstddef>
template<class T, std::enable_if_t<std::is_base_of_v<TClass, T>, std::nullptr_t> = nullptr>
class Foo
{
// Body
};
C++20:
#include <type_traits>
template<class T> requires std::is_base_of_v<TClass, T>
class Foo
{
// Body
};
C++14 和 C++11 支持非常相似的行为,但语法不太简洁,例如将std::is_base_of_v<TClass, T> 替换为std::is_base_of<TClass, T>::value。
【讨论】:
template<class T>
requires (std::is_base_of_v<TClass,T>)
class Foo{
};
请注意,这不是完全匹配,因为 Foo<A> 和 Foo<B> 在 C++ 中是不相关的类型。泛型和模板在一些相似的用例中仍然具有不同的功能。
泛型的完整模拟需要一个带有虚拟方法的基类,如果类型转换样板和派生模板覆盖并实现了我的经验中的一些细节,那么这些虚拟方法会做一堆。 (OTOH,这并不总是需要,模板做其他事情比泛型更容易)。
【讨论】:
在 C++ 中,我们很少使用基类来启用/禁用泛型。我认为这应该从我们对它的丑陋语法中可以看出,直到 C++20。
Pre-C++20,你只需使用类型,如果它有你想要的一切,它应该编译得很好。错误消息不太理想,但它很简单而且很有效:
template <class T>
class Foo { /* ... */ };
在 C++20 之后,我们有了“命名约束”的“概念”。它们类似于其他语言中的“接口”,但一切都在编译时解决。语法更好,您可以在示例中使用它们而不是基类:
template <class T>
concept TClass = ...;
template <TClass T>
class Foo { /* ... */ };
【讨论】: