1 2 3 4 5 6 7 8 9 10 11 |
//Листинг #1.1 Специализация функции template <typename T> //Обозначаем, что класс шаблонный class MyClass{ public: T foo(); //Прототип шаблонной функции класса }; template <> //специализация int MyClass<int>::foo() { //Функция пишется как обычно, но специализируемый тип указывается напрямую return 0; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
//Листинг #1.2 Специализация шаблона класса #include <iostream> using std::cin; using std::cout; /*ШАБЛОННЫЙ КЛАСС*/ template <typename T1> class MyClass { public: int foo(); }; template <typename T> int MyClass<T>::foo() { //Наиболее общий вариант решения return 0; } template <> //специализация class MyClass<char*>{ //шаблонного класса под тип char* public: int foo(); }; int MyClass<char*>::foo() { //Реализация под специализацию return 0; } int main() { cin.get(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
//Листинг #2 Обычный шаблонный класс без специализаций #include <iostream> using std::cin; using std::cout; template <typename T1> //Обозначаем, что класс шаблонный class MyClass{ public: void swap(T1&, T1&); //Прототип шаблонной функции класса }; template <typename T1> void MyClass<T1>::swap(T1 &left, T1 &right) { //Наиболее обобщённая функция T1 temp; temp = left; left = right; right = temp; } template <typename T1, typename T2> void test(const char* info, T1 ix, T1 iy, T2 dx, T2 dy) { //Обычная шаблонная функция для вывода значений на экран cout << info << '\n'; cout << "ix = " << ix << '\t'; cout << "iy = " << iy << '\n'; cout << "dx = " << dx << '\t'; cout << "dy = " << dy << '\n'; cout << '\n'; } int main() { int ix = 100, iy = 200; double dx = 100.5, dy = 200.5; MyClass<int> int_object; MyClass<double> double_object; test("before:", ix, iy, dx, dy); //выводим на экран значения (до смены) int_object.swap(ix, iy); //меняем местами double_object.swap(dx, dy); test("after:", ix, iy, dx, dy); //выводим на экран значения (после смены) cin.get(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
//Листинг #3 Обычный шаблонный класс без специализаций #include <iostream> using std::cin; using std::cout; template <typename T1> //Обозначаем, что класс шаблонный class MyClass{ public: void swap(T1&, T1&); //Прототип шаблонной функции класса }; template <typename T1> void MyClass<T1>::swap(T1 &left, T1 &right) { //Наиболее обобщённая функция T1 temp; temp = left; //Когда в T1 попадает char[255], то нельзя присвоить массив в массив! left = right; right = temp; } template <typename T1, typename T2> void test(const char* info, T1 ix, T1 iy, T2 dx, T2 dy) { //Обычная шаблонная функция для вывода значений на экран cout << info << '\n'; cout << "ix = " << ix << '\t'; cout << "iy = " << iy << '\n'; cout << "dx = " << dx << '\t'; cout << "dy = " << dy << '\n'; cout << '\n'; } int main() { int ix = 100, iy = 200; char S1[255] = " Hello "; char S2[255] = " WORLD! "; MyClass<int> int_object; MyClass<char[255]> str_object; test("before:", ix, iy, S1, S2); //выводим на экран значения (до смены) int_object.swap(ix, iy); //меняем местами, всё ОК str_object.swap(S1, S2); //А тут сюрприз! test("after:", ix, iy, S1, S2); //выводим на экран значения (после смены) cin.get(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
//Листинг #3 специализация Ошибка при написании кода #include <iostream> #include <cstring> using std::cin; using std::cout; template <typename T1> class MyClass { public: void swap(T1, T1); }; template <typename T1> void MyClass<T1>::swap(T1 left, T1 right) { T1 temp; temp = left; left = right; right = temp; } template <> void MyClass<char*>::swap(char* left, char* right){ char temp[255]; //Для сокращения кода допущение, что строки вмещают 255 символов //нужно, чтобы каждый массив мог вместить в себя каждый, иначе будут проблемы. strcpy(temp, left); //меняем местами строки путём копирования strcpy(left, right); strcpy(right, temp); } template <typename T1, typename T2> void test(const char* info, T1 ix, T1 iy, T2 dx, T2 dy) { cout << info << '\n'; cout << "ix = " << ix << '\t'; cout << "iy = " << iy << '\n'; cout << "dx = " << dx << '\t'; cout << "dy = " << dy << '\n'; cout << '\n'; } int main() { int ix = 100, iy = 200; char S1[255] = " Hello "; char S2[255] = " WORLD! "; MyClass<int> int_object; MyClass<char*> str_object; test("before:", ix, iy, S1, S2); int_object.swap(ix, iy); str_object.swap(S1, S2); test("after:", ix, iy, S1, S2); cin.get(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
//Листинг #4 Специализируем функцию шаблоннного класса Меняем местами однотипные объекты #include <iostream> #include <cstring> using std::cin; using std::cout; template <typename T1> class MyClass { public: void swap(T1&, T1&); }; template <typename T1> void MyClass<T1>::swap(T1& left, T1& right) { T1 temp; temp = left; left = right; right = temp; } template <> //Специализируем функцию шаблонного класса void MyClass<char [255]>::swap(char (&left)[255], char (&right)[255]){ //Не забываем в параметре класса указать правильный тип, сейчас char[255], в параметрах функции принимаются ссылки на массив char temp[255]; //Для сокращения кода допущение, что максимальная длина вошедшей строки 255 символов //В идеале вычислять большую длину и от неё создавать массив strcpy(temp, left); //меняем местами строки путём копирования strcpy(left, right); strcpy(right, temp); } template <typename T1, typename T2> void test(const char* info, T1 ix, T1 iy, T2 dx, T2 dy) { cout << info << '\n'; cout << "ix = " << ix << '\t'; cout << "iy = " << iy << '\n'; cout << "dx = " << dx << '\t'; cout << "dy = " << dy << '\n'; cout << '\n'; } int main() { int ix = 100, iy = 200; char S1[255] = " Hello "; char S2[255] = " WORLD! "; MyClass<int> int_object; MyClass<char[255]> str_object; test("before:", ix, iy, S1, S2); int_object.swap(ix, iy); str_object.swap(S1, S2); test("after:", ix, iy, S1, S2); cin.get(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
// Листинг #5 Специализируем сам шаблонный класс Меняем местами однотипные объекты #include <iostream> using std::cin; using std::cout; template <typename T1> class MyClass { public: void swap(T1&, T1&); }; template <typename T1> void MyClass<T1>::swap(T1 &left, T1 &right) { T1 temp; temp = left; left = right; right = temp; } template <> //Специализация class MyClass<char *> { //Шаблона класса public: void swap(char *, char *); }; void MyClass<char *>::swap(char * left, char * right) { MyClass<char> symbols_swapper; //left[0], left[1] ... — это первая пришедшая строка посимвольно //right[0], right[1] ... — это вторая пришедшая строка посимвольно //MyClass<char> — это класс, меняющий одиночные символы, объект его будет менять местами вытаскиваемый символ первой строки с вытаскиваемым символом второй //Чтобы смена произошла успешно, строка left должна суметь уместиться в right и наоборот, иначе будут проблемы //В примере этого кода подразумевается, что максимальная вместимость обеих вошедших строк одинаковая, для упрощения кода //Максимальную вместимость строк узнавать необязательно, копирование мусорных значений транжирство //У строки есть признак-опознователь конца: нулевой, на него и ориентируемся при посимвольном обходе int len = strlen(left) + 1; //Вытаскиваем длину/ +1 нужен для копирования самого признака for (int i = 0; i < len; i++) { symbols_swapper.swap(left[i], right[i]); //Вытаскиваем соответствующие по позиции символы из строк и меняем их объектом нашего класса обмена } } template <typename T1, typename T2> void test(const char* info, T1 ix, T1 iy, T2 dx, T2 dy) { cout << info << '\n'; cout << "ix = " << ix << '\t'; cout << "iy = " << iy << '\n'; cout << "dx = " << dx << '\t'; cout << "dy = " << dy << '\n'; cout << '\n'; } int main() { int ix = 100, iy = 200; char S1[255] = " Hello "; char S2[255] = " WORLD! "; MyClass<int> int_object; MyClass<char*> str_object; test("before:", ix, iy, S1, S2); int_object.swap(ix, iy); //Меняем обычные переменные местами str_object.swap(S1, S2); //Меняем массивы символов местами test("after:", ix, iy, S1, S2); cin.get(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
//Листинг #6 Специализация шаблона класса требует себе объявления всех функций-членов класса Пример на сложении #include <iostream> #include <cstring> using namespace std; /*ШАБЛОН КЛАССА*/ template <typename T> class MyClass{ T x, y; //Шаблонные параметры класса public: MyClass(const T &, const T &) ; //Прототип шаблонного конструктора класса T Add() { return x + y; } //Шаблонный метода класса (не вынесен за класс) }; /*ШАБЛОННЫЙ КОНСТРУКТОР КЛАССА*/ template <typename T> MyClass<T>::MyClass(const T &num1, const T &num2):x(num1),y(num2){}; /*СПЕЦИАЛИЗАЦИЯ ШАБЛОНА КЛАССА*/ template <> //Обозначили специализацию class MyClass<const char*>{ //В угловых скобках тип для корректировки поведения char *x; public: MyClass(const char* , const char* ); //Прототип специализированного конструктора const char *Add() {return x;}; //Прототип специализированного метода класса ~MyClass(); //Прототип деструктора специализированного класса }; /*КОНСТРУКТОР СПЕЦИАЛИЗИРОВАННОГО КЛАССА*/ MyClass<const char*>::MyClass(const char* s1, const char* s2){ unsigned len1 = strlen(s1); unsigned len2 = strlen(s2); x = new char[len1 + len2 + 1]; //Выделили нужное число памяти strncpy(x,s1,len1); strncpy(x+len1,s2,len2+1); } /*ДЕСТРУКТОР СПЕЦИАЛИЗИРОВАННОГО КЛАССА*/ MyClass<const char*>::~MyClass(){ delete []x; //Почистили память. } int main(){ MyClass<int> A1(100,200); cout<<A1.Add()<<"\n"; MyClass<const char*> A2("hello","bye"); cout<<A2.Add(); } |
Привет, дорогой автор!
Почему в этом фрагменте должна быть проблема в первой строчке ?
MyClass<const char*> X2(«Hello»,»Bye»); //<— Заработало
std::cout<<X2.Add();
Специализируется ведь вторая строчка?
Да. Специализируется ради std::cout << X2.Add();
Конечно, проблемы быть не должно. У меня в коде переопределение X2. Сбило с толку, наверное, когда писал.
Позже будет исправлено.