没有模板参数的抽象类的实现

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&lt;T&gt; 类以使其没有模板参数吗? 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&lt;1, int&gt;x&lt;2, int&gt;,但它们不仅仅是不同的对象,而是不同的类型。因此,在您的情况下,您的 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_iftype_traits 中包含的其他模板魔法。

您正在寻找的是概念,这些概念甚至没有构成 C++17,或类型类(在其他语言中可用,如 Haskell 或 Scala)

如果您真的想在这里使用面向对象的方法,请使用以下方法:

template <typename Value> 
class Dict 
    Dict(std::shared_ptr<Hashable>, Value) 
    

但是,这不是典型的实现,所以我不会推荐它

【讨论】:

是否可以用两个基类(即template &lt;Hashable, Equatable Key, typename V&gt; ...)专门化一个模板参数? 这些不是基类——这就是你的类型参数。您的示例定义了一个带有三个参数的模板:一个是 Hashable 类型,一个是 Equatable 类型,一个是任意类型。您似乎在模仿 Haskell 的类型类语法——它在 C++ 中不能这样工作。如果你想在模板参数中强加基类依赖或任意方法的存在,你必须使用type_traits。通过使用type_traits,您可以编写任意数量的约束。 当然我不想定义一个带有三个参数的模板,我的例子只是为了展示我想要做什么。无论如何,谢谢。

以上是关于没有模板参数的抽象类的实现的主要内容,如果未能解决你的问题,请参考以下文章

模板类与抽象类

9.抽象类和接口

接口 interface ,抽象类 abstract

抽象类抽象方法final

抽象类

模板方法设计模式