Мне интересно, возможно ли иметь класс, который использует template<typename T>
с функциями, которые «typename T» использует по умолчанию. Я приведу примеры:
Заголовок:
includes all here
extern template class Object<rectangleBase>
extern template class Object(circleBase>
struct rectangleBase
{
int width, height;
int posX, posY;
};
struct circleBase
{
int radius;
int posX, posY;
};
template<typename T>
class Object {
public:
Object();
~Object();
void movePos(int x, int y);
void setPos(int x, int y);
T& returnObject() {
return object;
}
private:
T object;
};
Источник:
includes all here
template class Object<rectangleBase>
template class Object<circleBase>
Object<rectangleBase>::Object() {
rectangleBase* newObject;
newObject = new rectangleBase;
object = *newObject;
}
Object<circleBase>::Object() {
circleBase* newObject;
newObject = new circleBase;
object = *newObject;
}
void Object::movePos(int x, int y) { //here
object.posX += x;
object.posY += y;
}
void Object::setPos(int x, int y) { //here
object.posX = x;
object.posY = y;
}
С помощью функций setPos и movePos возможно, что оба <rectangleBase>
а также <circleBase>
может использовать одну и ту же функцию вместо того, чтобы мне приходилось писать один и тот же код дважды, потому что они использовали бы один и тот же код, я покажу, где находятся функции в коде.
Если это невозможно, есть ли альтернатива?
Наличие одного и того же кода для нескольких разных типов данных (в общем, общее программирование) — это как раз то, для чего нужны шаблоны. Я думаю, что вы слишком обдумываете вещи. Для вашего варианта использования достаточно:
template<typename T>
class Object {
public:
Object()
: object()
{ }
void movePos(int x, int y) {
object.posX += x;
object.posY += y;
}
void setPos(int x, int y) {
object.posX = x;
object.posY = y;
}
T& returnObject() {
return object;
}
private:
T object;
};
Это все, что вам нужно. Это будет работать для любого T
то есть конструируемый по умолчанию, а затем movePos
а также setPos
можно назвать, если T
имеет эти две переменные-члены. Вам не нужно объявлять специализации вообще. Учитывая вышеизложенное, отлично работает следующее:
Object<rectangleBase> r;
r.setPos(5, 6);
Object<circleBase> c;
c.setPos(10, 20);
s.movePos(10, 10);
Я не уверен, в чем твоя проблема. Вы должны просто реализовать свои функции, создать экземпляр шаблона и использовать ваши объекты.
Я пытался, это работает. Пожалуйста, взгляните: http://ideone.com/717044
#include <stdio.h>
struct rectangleBase
{
int width, height;
int posX, posY;
};
struct circleBase
{
int radius;
int posX, posY;
};
template<typename T>
class Object {
public:
Object() { }
~Object() { }
void movePos(int x, int y)
{
object.posX += x;
object.posY += y;
}
void setPos(int x, int y)
{
object.posX = x;
object.posY = y;
}
T& returnObject() { return object; }
private:
T object;
};
int main(int argc, char ** argv)
{
Object<rectangleBase> a;
Object<circleBase> b;
b.setPos(1,2);
printf("px: %d", b.returnObject().posX);
}
Если вам интересно, сколько экземпляров компилятора функций будет сгенерировано,
(пример: код ваших функций огромен), скорее всего, компилятор сгенерирует столько экземпляров схожего кода, сколько у вас будет различных экземпляров. Оптимизатор может свернуть некоторые из них. Но если оптимизатор это сделает или нет — сказать сложно.
Подход, когда вы используете поля, методы, перечисления и т. Д. Типов параметров непосредственно из тела шаблона, вызывается с использованием зависимых типов. Да, такой подход затрудняет или делает невозможным создание экземпляра шаблона с типами, которые не имеют этого поля или функции-члена. Тем не менее, эта модель широко используется.
Да, ты можешь:
template <typename T>
void Object<T>::movePos(int x, int y) {
object.posX += x;
object.posY += y;
}
Даже ваши конструкторы могут использовать этот подход:
template <typename T>
Object<T>::Object() {
// This in fact does nothing really different than the default
// constructor of object but leaks one instance of T.
T* newObject;
newObject = new T;
object = *newObject;
}
Для шаблонов обычно требуется полная реализация в заголовочных файлах, но если вы хорошо работаете с ограниченными типами, которые приняты, вы можете явно создать экземпляры классов, а затем получить реализацию в исходном файле:
В заголовочном файле (в любом месте после определения класса):
extern template class Object<rectangleBase>;
extern template class Object<circleBase>;
В исходном файле (где угодно после определения методов):
template class Object<rectangleBase>;
template class Object<circleBase>;
Любой другой тип, чем rectangleBase
или же circleBase
не будет работать с этой настройкой.