Почему мне не нужно определять одни и те же члены, когда я делаю полную специализацию шаблона класса в C ++? - PullRequest
5 голосов
/ 14 июня 2011

Я очень удивлен, обнаружив, что следующие компиляции:

#include <iostream>

using namespace std;

template<typename T>
class SomeCls {
public:
  void UseT(T t) {
    cout << "UseT" << endl;
  }
};

template<>
class SomeCls<int> {
  // No UseT? WTF?!??!?!
};

int main(int argc, char * argv[]) {
  SomeCls<double> d;
  SomeCls<int> i;

  d.UseT(3.14);
  // Uncommenting the next line makes this program uncompilable.
  // i.UseT(100);

  return 0;
}

Почему это разрешено?Просто кажется неправильным, что class SomeCls<int> не нужно иметь void UseT(T t) метод.Я уверен, что здесь не хватает специализации (я не эксперт по С ++).Может кто-нибудь, пожалуйста, просветите меня?

Ответы [ 4 ]

11 голосов
/ 14 июня 2011

Потому что SomeCls<double> - это совершенно другой тип, чем SomeCls<int> или любой другой SomeCls<T>.Они никоим образом не связаны, поэтому они могут иметь любого члена, которого они хотят.Только не вызывайте i.UseT(), именно здесь компилятор начнет жаловаться, конечно.

7 голосов
/ 14 июня 2011

Специализация может специализироваться любым удобным для вас способом.Если вы хотите опустить все методы, добавить или удалить базовые классы, добавить или удалить элементы данных, то это нормально.

template <class T>
class Foo {};

template <>
class Foo<int> { void extrafunc(); }; //fine

template <>
class Foo<bool> : public ExtraBase {}; // fine

template <>
class Foo<double> { int extradata; }; // fine

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

template <class T>
void foo(const T&);

template <>
void foo<int>(int); // not fine, must be const int&

void foo(int); // fine, this is an overload, not a specialisation

template <class T>
void foo(T*); // fine, again this is an overload, not a specialisation
0 голосов
/ 15 июня 2011

Я пометил ответ как "правильный", но я не очень доволен. я не спрашивать, КАК это работает; Я спрашиваю, почему это был разработан таким образом. Как это работы не кажутся мне последовательными с ОО. Это даже кажется последовательным. Почему функционирует шаблон специализация имеет ограничение что интерфейс должен быть согласованным, в то время как специализация шаблона класса не ??

Если бы это был ваш вопрос, вам, вероятно, следовало бы так сказать с самого начала.

Я собираюсь начать с последнего бита: почему функции требуют одинаковых подписей. Это легко, функции уже могут повторно использовать имена через перегрузку.

int f(int);
double f(double); //no templates needed

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

В случае типов классов шаблон гораздо сложнее. Мало того, что у вас есть функции-члены для рассмотрения, у вас есть объекты-члены, typedefs, вложенные типы и так далее. Специализация всех тех. Если для SomeTemplatedObject<double> требуется определенный закрытый член, который SomeTemplatedObject<T> обычно не требуется, как вы можете специализировать SomeTemplatedObject для double без изменения «интерфейса»? Или что из методов, которые не имеют смысла для определенных типов? Или вложенные типы, которые необходимо изменить, чтобы сохранить согласованный интерфейс? И это даже не касается более широкой проблемы шаблонного метапрограммирования.

Вам даже не нужно иметь полный тип для общего случая.

template<typename T>
struct Object;

template<>
struct Object<int> { //what interface does this need?
  typedef int type;
};

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

0 голосов
/ 14 июня 2011

Ваш код никогда не вызывает версию UseT int, поэтому вам не нужно предоставлять ее.

...