问题
In the sample:
#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;
}
I get the following error:
test.cpp:(.text+0x1c): undefined reference to `D<bool>::D()'
Note that the reason I don't just specialize the D() by itself is I want to eliminate the need for string D<T>::data
in the D<bool>
case.
Why do I need to re-implement D()
in D<bool>
? Seems like there should be a way for me to tell the compiler to use the version from D<T>
.
Is there any way to do a simple specialization like this without having to re-implement methods?
回答1:
No, there is not.
Specialization is behaving very differently than inheritence. It has no connection to the generic template version.
When you use/instantiate a template, the compiler will create a new type name, and then look for how this type is defined. When it finds a specialization, then it takes that as the definition for the new type. When it does not, it takes the generic template and instantiates it.
Therefore they have no connection, and you are just writing an entirely new class, just with a special name for the compiler to find in case of someone using/instantiating the template to find it under that name.
回答2:
Each specialisation of a class template gives a different class - they do not share any members with each other. Since you've explicitly specialised the entire class, you don't get any of the members from the template, and must implement them all.
You can explicitly specialise individual members, rather than the entire class:
template <> void D<bool>::pvf(){ cout << "bool type" << endl; }
Then D<bool>
will still contain all the members of the class template that you haven't explicitly specialised, including the default constructor.
回答3:
The problem is your erroneous assumption that there is anything common between D<A>
and D<B>
. Template instances are types, and two different instances are two different types, end of story. It only so happens that instances of the same template have formally similar code, but with specialization you can define any type you like. In short, every type that you define explicitly is entirely independent, and there is no commonality across specialized template instances, even if they happen to have the same name.
For example:
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> &);
};
The types Foo<char>
and Foo<int>
have nothing to do with one another, and there is no reason why any part of one should have any use inside the other.
If you want to factor out common features, use private inheritance:
template <typename> struct D : private DImpl { /* ... */ }
回答4:
You need to reimplement it because D<T>
and D<bool>
are totally unrelated classes (they just happen to "share the name"). That's just how templates work.
If you want the classes to share construction code, just put that code inside B::B
(i.e. the same thing you do every time you want to reuse code in different branches of the same hierarchy: move the code up and let inheritance handle the rest).
回答5:
Consider that D<T>::D()
will be responsible for default-constructing string data
, and that D<bool>
doesn't have any such member. Clearly there is no way to use the same emitted code in each case.
However, if your default constructor doesn't do anything (in either version here), just omit it and allow the compiler to do the work.
来源:https://stackoverflow.com/questions/8789867/c-template-class-specialization-why-do-common-methods-need-to-be-re-implement