【问题标题】: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,因为哈希性应该需要它。

所以,我有两个问题:

  1. 我们可以重写Equatable&lt;T&gt; 类以使其没有模板参数吗? C++ 是否有任何关键字引用当前类的类型?

  2. 在我看来,Hashable 最好继承自 Equatable 类。如何在没有Hashable 上的新模板定义的情况下实现这一点(如果我的第一个问题的答案是肯定的,那么这已经解决了)?

  3. 这里最好的面向对象方法是什么?拥有一个带有模板参数的接口类似乎很俗气。

谢谢。

【问题讨论】:

  • 我认为您实际上是在寻找类型类机制,这在 C++ 中并不是很好。从 C++11 开始就计划了一种概念机制,但它甚至没有实现到 C++17 (honermann.net/blog/?p=3)

标签: c++ inheritance abstract-class


【解决方案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 是我所知道的唯一实现。
【解决方案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,您可以编写任意数量的约束。
  • 当然我不想定义一个带有三个参数的模板,我的例子只是为了展示我想要做什么。无论如何,谢谢。
猜你喜欢
  • 1970-01-01
  • 2014-11-02
  • 2017-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
相关资源
最近更新 更多