2012-01-09 3 views
11

В образце:C++ класс специализация шаблона: почему общие методы должны быть повторно реализованы

#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()' 

Обратите внимание, что причина, я не» t просто специализируюсь на D() самостоятельно, я хочу устранить необходимость в строке D<T>::data в корпусе D<bool>.

Зачем мне нужно переоснастить D() в D<bool>? Похоже, должен быть способ сообщить мне компилятору использовать версию от D<T>.

Есть ли способ сделать простую специализацию как это без необходимости повторного внедрения методов?

+0

Потому что это совершенно новый тип. –

ответ

10

Нет, нет.

Специализация ведет себя по-разному, чем наследование. Он не имеет отношения к общей версии шаблона.

Когда вы используете/создаете экземпляр шаблона, компилятор создаст новое имя типа и затем определит, как этот тип определен. Когда он находит специализацию, он принимает это как определение для нового типа. Когда этого не происходит, он принимает общий шаблон и создает его.

Поэтому у них нет связи, и вы просто пишете совершенно новый класс, просто со специальным именем для компилятора, чтобы найти в случае, если кто-то использует/создает экземпляр шаблона, чтобы найти его под этим именем.

+7

К сожалению, – Jaime

1

Вам необходимо переопределить его, потому что D<T> и D<bool> - совершенно несвязанные классы (они просто «делят имя»). Вот как работают шаблоны.

Если вы хотите, чтобы классы делились строительным кодом, просто введите этот код внутри B::B (то есть то же самое, что вы делаете каждый раз, когда хотите повторно использовать код в разных ветвях одной и той же иерархии: переместите код вверх и разрешите наследование отдых).

12

Каждая специализация шаблона класса дает другой класс - они не разделяют каких-либо членов друг с другом. Поскольку вы явно специализировали весь класс, вы не получаете ни одного из членов шаблона и должны реализовать их все.

Вы можете явно специализировать отдельные элементы, а не весь класс:

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

Тогда D<bool> еще будет содержать все элементы шаблона класса, который явным образом не специализированные, в том числе конструктор по умолчанию.

+0

Ударьте меня на это на 21 секунду (но только потому, что я должен был проверить это, чтобы убедиться, что это возможно :)) +1 –

+0

Я знаю, что вы можете специализировать методы, вот почему я добавил примечание о том, m не делаю этого ... Моя цель состоит в том, чтобы иметь член данных в одном, а не в другом, и не нужно повторно реализовывать распространенные методы. Я понимаю, что происходит, просто не понимаю, почему обычный метод не может быть повторно использован. – Jaime

4

Проблема в том, ваше ошибочное предположение, что есть что-то общее между 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 { /* ... */ } 
+0

Прекратите принимать мои мысли и формировать их как ваш ответ! :( – Xeo

+0

@Xeo: наденьте свою оловянную колпачку! –

+0

Не делайте никаких предположений, просто интересно, почему я не могу сказать компилятору использовать стандартную реализацию для шаблона. Я понимаю, что каждый тип шаблона - это другой тип, независимо от специализации , но это касается моей точки зрения. Если компилятор может использовать один и тот же метод для обоих типов, почему бы не для специализации, если не существует конфликтов – Jaime

0

Считают, что D<T>::D() будет нести ответственность за неисполнение-строящейся string data, и что D<bool> не имеет такого члена. Очевидно, что в каждом случае нельзя использовать один и тот же испускаемый код.

Однако, если ваш конструктор по умолчанию ничего не делает (в либо здесь), просто опустите его и разрешите компилятору выполнять работу.

+0

Такая же проблема с другим методом, кроме конструктора. – Jaime