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

时间:2012-01-09 14:21:17

标签: c++ templates specialization

在样本中:

#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<T>::data情况下消除字符串D<bool>的需要。 < / p>

为什么我需要在D()中重新实施D<bool>?好像我应该告诉编译器使用D<T>中的版本。

有没有办法像这样做一个简单的专业化而不必重新实现方法?

5 个答案:

答案 0 :(得分:15)

类模板的每个特化都会提供不同的类 - 它们不会彼此共享任何成员。由于您已明确专门化了整个类,因此您无法从模板中获取任何成员,并且必须全部实现它们。

您可以明确地专门化个别成员,而不是整个班级:

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

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

答案 1 :(得分:11)

不,没有。

专业化的行为与继承的行为截然不同。它与通用模板版本无关。

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

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

答案 2 :(得分:5)

问题是您错误地假设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 { /* ... */ }

答案 3 :(得分:1)

您需要重新实现它,因为D<T>D<bool>是完全无关的类(它们碰巧“共享名称”)。这就是模板的工作原理。

如果您希望这些类共享构造代码,只需将该代码放在B::B中(即每次要在同一层次结构的不同分支中重用代码时都要执行的操作:将代码移动到让继承处理剩下的事情。)

答案 4 :(得分:0)

考虑D<T>::D()将负责默认构建string data,并且D<bool>没有任何此类成员。显然,在每种情况下都无法使用相同的发射代码。

但是,如果你的默认构造函数没有做任何事情(在 版本中),只需省略它并允许编译器完成工作。