【问题标题】:Explicit Specialization of a Derived Class Template派生类模板的显式特化
【发布时间】:2020-07-13 01:15:23
【问题描述】:

我有一个实现许多功能的类模板。当声明特定类型时,我还希望能够添加此类的专用版本,该版本只有少数功能覆盖基类的功能。我知道我可以通过一个类模板和它的显式特化来实现这一点。不过我也想:

  • 具有唯一命名的显式特化,类似于如何唯一命名基类和派生类。
  • 从实例化的Derived 对象调用Base 函数,可以在Derived 函数内部,也可以如下使用obj1.Foo 显式调用

这是我正在尝试制作的(简化的)示例代码:

在 myClasses.h 中

template<typename T>
class Base
{
  public: 
    void Foo (T& input);
    virtual void Bar (T& input);
}

template<>
class Derived : public Base<int>
{
  public: 
    void Bar (int& input) override;
}

在 myClasses.cpp 中

template<typename T>
Base::Foo(T& input) { // Do something generic }

template<typename T>
Base::Bar(T& input) { // Do something generic }

template<>
Derived::Bar(int& input) { // Do something int-dependent }

在 main.cpp 中

int main()
{
  Base<int> obj1 = new Derived();
  obj1.Foo(input);                  // Runs Base::Foo
  obj1.Bar(input);                  // Runs Derived::Bar
}

但是,此代码失败并出现 explicit specialization of non-template Derived 错误等。我已经阅读了很多 StackOverflow 线程来让我走到这一步,但我还没有找到任何可以帮助我进行编译的东西。所以我的问题是:

  1. 是否可以通过这种方式将类模板与类继承结合起来?
  2. 为什么编译器将派生类标记为非模板,尽管我明确使用了该关键字?
  3. 什么是使该代码工作的正确语法? (假设我正在尝试做的事情是可能的)

编辑: 按照 HTNW 的建议,我可以通过删除 template&lt;&gt; 前缀将 Derived 变为常规类。这将允许一切编译到obj1.Foo(input)。实例化的 Derived 类似乎无法找到或访问基 Foo 函数。

【问题讨论】:

  • 您没有Derived 模板,只有专业化。需要有一个模板来专门...
  • 为什么你不能只制作Derived...而不是模板? class Derived : public Base&lt;int&gt; { ... };。将模板与继承“结合”的唯一方法对我来说有意义,然后使用类型特征通过选择T:template&lt;typename T&gt; impl_for { using type = Base&lt;T&gt;; }; template&lt;&gt; impl_for&lt;int&gt; { using type = Derived; }; 来查找派生类。
  • @Matt ?您的意思是您未能构造Derived 类型的对象吗?那是因为new Derived() 没有Derived 类型:它在堆上分配Derived,在那里构造它,并返回指向它的Derived*。修复,从最差到最好:Base&lt;int&gt; *obj1 = new Derived();std::unique_ptr&lt;Base&lt;int&gt;&gt; obj1 = std::make_unique&lt;Derived&gt;();Base&lt;int&gt; &amp;&amp;obj = Derived();。请注意,第一个泄漏内存。这就是为什么你不应该使用new
  • @Matt Base 的特化可以是,例如,template&lt;&gt; Base&lt;int&gt;。这使您可以替换 Base 的定义,据说比一般模板提供的更适合整数。这对类模板很少有用,但有时对函数模板有用。
  • @ravnsgaard 恰恰相反——它对类更有用(例如,参见特征),但通常不建议专门化函数模板(重载是首选)。

标签: c++ templates template-specialization explicit-specialization


【解决方案1】:

感谢 ravnsgaard 和 HTNW 提供的有用建议,帮助我找到了解决方案。关键是从Derived 类中删除template&lt;&gt; 关键字(因为我希望它是一个类而不是类模板)并在源文件末尾声明Base&lt;int&gt;。所以工作代码如下所示:

在 myClasses.h 中

template<typename T>
class Base
{
  public: 
    void Foo (T& input);
    virtual void Bar (T& input);
}

class Derived : public Base<int>
{
  public: 
    void Bar (int& input) override;
}

在 myClasses.cpp 中

template<typename T>
Base::Foo(T& input) { // Do something generic }

template<typename T>
Base::Bar(T& input) { // Do something generic }

Derived::Bar(int& input) { // Do something int-dependent }

template class Base<int>; // VERY IMPORTANT.

在 main.cpp 中

int main()
{
  Base<int> &&obj1 = Derived();
  obj1.Foo(input);                  // Runs Base::Foo
  obj1.Bar(input);                  // Runs Derived::Bar
}

特别是,如果 myClasses.cpp 末尾没有 template class Base&lt;int&gt;; 声明,对 obj1.Foo 的调用将失败,并出现错误,抱怨 Derived 没有这样的功能。

【讨论】:

    猜你喜欢
    • 2018-01-22
    • 1970-01-01
    • 2010-12-28
    • 1970-01-01
    • 1970-01-01
    • 2016-09-26
    • 1970-01-01
    • 2021-11-16
    • 2017-02-10
    相关资源
    最近更新 更多