C++模板类专用化:为什么需要重新实现常见方法

C++ template class specialization: why do common methods need to be re-implemented

本文关键字:新实现 实现 方法 常见 专用 为什么 C++      更新时间:2023-10-16

在示例中:

#include <iostream>
using namespace std;
class B
{
public:
    virtual void pvf() = 0;
};
template <class T>
class D : public B
{
public:
    D(){}
    virtual void pvf() {}
private:
    string data;
};
template <>
class D<bool> : public B
{
public:
    D();
    virtual void pvf(){ cout << "bool type" << endl; }
};
int main()
{
    D<int> d1;
    D<bool> d2;
}

我得到以下错误:

test.cpp:(.text+0x1c): undefined reference to `D<bool>::D()'

注意,我不只是专门化D()本身的原因是,我想在D<bool>的情况下消除对字符串D<T>::data的需要

为什么我需要在D<bool>中重新实现D()?似乎应该有一种方法让编译器使用D<T>的版本。

有没有什么方法可以在不需要重新实现方法的情况下完成这样一个简单的专业化?

类模板的每个专业化都会产生不同的类-它们之间不共享任何成员。由于您已经明确地专门化了整个类,因此您不会从模板中获得任何成员,必须全部实现它们。

您可以明确地专门针对单个成员,而不是整个类别:

template <> void D<bool>::pvf(){ cout << "bool type" << endl; }

然后D<bool>将仍然包含类模板中所有您尚未明确指定的成员,包括默认构造函数。

不,没有。

专业化的表现与继承截然不同。它与通用模板版本没有连接。

当您使用/实例化模板时,编译器将创建一个新的类型名称,然后查找如何定义此类型。当它找到一个特殊化时,它会将其作为新类型的定义。如果没有,它会获取通用模板并实例化它

因此,它们没有连接,您只是在编写一个全新的类,只是为编译器提供一个特殊的名称,以防有人使用/实例化模板以该名称查找它。

问题是您错误地认为D<A>D<B>之间有任何公共。模板实例是类型,两个不同的实例是两种不同的类型,故事结束。只有当相同模板的实例具有形式上相似的代码时,才会发生这种情况,但通过专门化,您可以定义任何您喜欢的类型。简而言之,您显式定义的每个类型都是完全独立的,并且在专门的模板实例之间没有通用性,即使它们碰巧具有相同的名称。

例如:

template <typename T> struct Foo
{
    T & r;
    const T t;
    void gobble(const T &);
    Foo(T *);
};
template <> struct Foo<int>
{
    std::vector<char> data;
    int gobble() const;
    Foo(bool, int, Foo<char> &);
};

类型Foo<char>Foo<int>彼此无关,也没有理由让其中一个的任何部分在另一个内部有任何用途。

如果你想排除常见的功能,可以使用私有继承:

template <typename> struct D : private DImpl { /* ... */ }

您需要重新实现它,因为D<T>D<bool>是完全不相关的类(它们只是碰巧"共享名称")。模板就是这样工作的。

如果您希望类共享构造代码,只需将该代码放入B::B中即可(即,每次您希望在同一层次结构的不同分支中重用代码时所做的相同操作:向上移动代码,让继承处理其余部分)。

考虑D<T>::D()将负责默认构造string data,而D<bool>没有任何这样的成员。显然,在每种情况下都无法使用相同的已发出代码。

但是,如果您的默认构造函数什么都不做(在版本中),只需省略它,并允许编译器完成工作。