没有模板参数的抽象类的实现
Posted
技术标签:
【中文标题】没有模板参数的抽象类的实现【英文标题】:Implementation of abstract class without template argument 【发布时间】:2016-04-14 13:52:32 【问题描述】:我想像这样实现两个简单的抽象类:
class Hashable
public:
virtual Int hashValue() = 0;
;
template <typename T>
class Equatable
virtual Bool operator == (const T& other) = 0;
这些类将使我有机会在我的新字典类中进行部分模板专业化。
但是,我无法让它们工作。这是我的字典类的声明:
template <Hashable Key, typename Value>
class Dictionary
.
.
.
;
问题是,key 也应该是Equatable
,因为哈希性应该需要它。
所以,我有两个问题:
我们可以重写Equatable<T>
类以使其没有模板参数吗? C++ 是否有任何关键字引用当前类的类型?
在我看来,Hashable
最好继承自 Equatable
类。如何在没有Hashable
上的新模板定义的情况下实现这一点(如果我的第一个问题的答案是肯定的,那么这已经解决了)?
这里最好的面向对象方法是什么?拥有一个带有模板参数的接口类似乎很俗气。
谢谢。
【问题讨论】:
我认为您实际上是在寻找类型类机制,这在 C++ 中并不是很好。从 C++11 开始就计划了一种概念机制,但它甚至没有实现到 C++17 (honermann.net/blog/?p=3) 【参考方案1】:您基本上在寻找的是概念,您可以使用它编写如下内容:
template <class T>
concept bool Hashable()
return requires(T t, T u)
t.hashValue() -> size_t;
t == u -> bool;
;
template <Hashable Key, class Value>
class Dictionary
...
;
但这甚至不会出现在 C++17 中。
在那之前,我们可以在 C++14 中使用 void_t
编写这种东西:
template <class...> using void_t = void;
template <class T, class = void>
struct Hashable : std::false_type ;
template <class T>
struct Hashable<T, void_t<
std::enable_if_t<std::is_same<std::declval<T&>().hashValue(), std::size_t>::value>,
decltype(std::declval<T&>() == std::declval<T&>())
>>
: std::true_type ;
template <class Key, class Value>
class Dictionary
static_assert(Hashable<Key>::value, "Key must be Hashable<>");
...
;
请注意,在这两种情况下,我们都要求 Key
类型具有此功能 - 我们不需要 Key
以虚拟方式继承它。这效率要高得多。无需虚拟调度。
这里最好的面向对象方法是什么?
不使用面向对象的方法。
【讨论】:
最新的clang有概念吗,或者你知道什么时候可以用吗? @Leviathlon 目前尚不清楚(如果曾经)概念何时会出现在 C++ 标准中。主干上的 gcc 6.0 是我所知道的唯一实现。 仅供参考,整个想法来源于developer.apple.com/library/watchos/documentation/Swift/…【参考方案2】:我相信
template <Hashable Key, typename Value>
实际上并没有做你期望它做的事情。考虑:
template <int Key, typename Value> class x;
现在,您可以实例化x<1, int>
和x<2, int>
,但它们不仅仅是不同的对象,而是不同的类型。因此,在您的情况下,您的 Hashable
对象将成为类型的一部分(因此它必须在编译期间生成,而不是在运行时生成)。
您最可能想要的是 - 就像另一个答案中提到的 Wojciech Frohmberg:
template <typename K, typename V>
class Dict
...
static_assert(std::is_base_of<K, Hashable>::value, "Only Hashable can be the key);
或enable_if
或type_traits
中包含的其他模板魔法。
您正在寻找的是概念,这些概念甚至没有构成 C++17,或类型类(在其他语言中可用,如 Haskell 或 Scala)
如果您真的想在这里使用面向对象的方法,请使用以下方法:
template <typename Value>
class Dict
Dict(std::shared_ptr<Hashable>, Value)
但是,这不是典型的实现,所以我不会推荐它
【讨论】:
是否可以用两个基类(即template <Hashable, Equatable Key, typename V> ...
)专门化一个模板参数?
这些不是基类——这就是你的类型参数。您的示例定义了一个带有三个参数的模板:一个是 Hashable 类型,一个是 Equatable 类型,一个是任意类型。您似乎在模仿 Haskell 的类型类语法——它在 C++ 中不能这样工作。如果你想在模板参数中强加基类依赖或任意方法的存在,你必须使用type_traits
。通过使用type_traits
,您可以编写任意数量的约束。
当然我不想定义一个带有三个参数的模板,我的例子只是为了展示我想要做什么。无论如何,谢谢。以上是关于没有模板参数的抽象类的实现的主要内容,如果未能解决你的问题,请参考以下文章