Твиттер || Facebook || Instagram || Средний или просто напишите мне по адресу || jayviveki13@gmail.com От Java до C++ – универсальное программирование шаблонов – это повседневный хлеб, возможно, для каждого программиста Java, кроме самого старого… С тегами cpp, новички, java, template.re. С Java на C++ (Серия из 2 частей) С Java на C++ – шаблоны
Твиттер || Facebook || Instagram || Средний или просто напишите мне по адресу || jayviveki13@gmail.com От Java до C++ – универсальное программирование шаблонов – это повседневный хлеб, возможно, для каждого программиста Java, кроме самого старого… С тегами cpp, новички, java, template.re. От Java до C++ (серия из 2 частей) Java до C++ – универсальное программирование шаблонов – это повседневный хлеб, возможно, для каждого программиста Java. Твиттер || Facebook || Instagram || Средний или просто напишите мне по адресу || jayviveki13@gmail.com От Java до C++ – универсальное программирование шаблонов – это повседневный хлеб, возможно, для каждого программиста Java, кроме самого старого… С тегами cpp, новички, java, template.re. От Java до C++ (серия из 2 частей) Java до C++ – шаблоны Универсальное программирование – это повседневный хлеб, возможно, для каждого, но самые старые программисты Java все еще помнят времена, когда мы бросали вещи повсюду, и списки создавались без явного указания компилятору, какой тип объектов они содержат. ава программист где-то там. Твиттер || Facebook || Instagram || Средний или просто напишите мне по адресу || jayviveki13@gmail.com От Java до C++ – универсальное программирование шаблонов – это повседневный хлеб, возможно, для каждого программиста Java, кроме самого старого… С тегами cpp, новички, java, template.re. От от Java до C++ (серия из 2 частей) Java до C++ – шаблоны Универсальное программирование – это повседневный хлеб, возможно, для каждого, только самые старые программисты Java все еще помнят, что не должно удивлять, что та же функциональность существует в старшем двоюродном брате Java – C++. были времена, когда мы бросали вещи повсюду, и списки создавались без явного указания компилятору, какой тип объектов они содержат. ава программист где-то там.
Твиттер Facebook
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ 2! Я не хотел начинать здесь полномасштабный урок истории. Я использую новейший стандарт C++20, и все примеры компилируются и работают в нем. Я могу время от времени указывать, когда была введена определенная функциональность.
Пойдем
Универсальное программирование на C++ строго связано с концепцией шаблона . Хотя в мире Java мы привыкли к идее дженериков , шаблоны в C++ немного отличаются и, на мой взгляд, сложнее для понимания. В этой статье я постараюсь сделать все возможное, чтобы представить универсальное программирование на C++ таким образом, чтобы каждый программист Java мог легко понять. Давайте начнем с определения шаблона , данного Страуструп сам.
По сути, шаблон – это механизм, который позволяет программисту использовать типы в качестве параметров для класса или функции. Затем компилятор генерирует определенный класс или функцию, когда мы позже предоставляем определенные типы в качестве аргументов.
Мы можем выбрать три отдельных типа шаблонов :
- шаблоны функций
- шаблоны классов
- шаблоны переменных (начиная с C++14)
Дополнительная типология поставляется с параметрами шаблона |, оцененными во время компиляции), другими словами, что может быть передано в качестве параметра в шаблон ключевое слово:
типы параметров – наиболее распространенные, например.
шаблон<имя типа|класс T>
нет -параметры типа – обычно уже заданное значение, например, число 6. Начиная с C++20, также возможно использовать числа с плавающей запятой и строки (массивы) в стиле C, хотя и с некоторыми ограничениями. Однако здесь можно использовать множество других типов в качестве перечислений, указателей всех видов или std::nullptr_t
шаблон-параметры шаблона – когда мы вводим шаблон в другой шаблон
Здесь мы должны помнить, что значение T имеет свою собственную область действия, ограниченную только шаблоном !
Шаблоны функций
Этот тип шаблонов должен быть хорошо знаком каждому программисту Java, так как они выглядят и работают так же, как дженерики в Java. Мы передаем функции некоторый универсальный класс/тип без каких-либо дополнительных предположений.
#includeusing namespace std; template // T is usually used to indicate first param, U to indicate second one T myMax(T x, T y) { return (x > y) ? x: y; } // Based on the calls to this function in the main() method // the template will be replaced with three separate // implementations of the above method using ints, doubles and // chars as input params. int main() { short myShort = 2; cout << myMax (3, 7) << endl; // Call myMax for int cout << myMax (myShort, 7) << endl; // ERROR - this won't compile as the params are not of the same type cout << myMax (3.0, 7.0) << endl; // call myMax for double cout << myMax ('g', 'e') << endl; // call myMax for char return 0; }
Первое, с чего нужно начать, – выше шаблон – это просто рецепт для создания конкретных определений функций . Процесс этого создания называется создание экземпляра шаблона .
Второе, что нужно обсудить, это следует ли нам использовать имя типа или класс или класс в определении шаблона . или класс в определении шаблона . Ну, насколько я читал, это не имеет большого значения (особенно в C++20). или
или класс в определении шаблона . Ну, насколько я читал, это не имеет большого значения (особенно в C++20). До того, как использование было каким-то образом ограничено, когда шаблоны шаблонов были вызваны, Подробнее об этом можно найти здесь
или класс в определении шаблона
templatevoid PrintNumbers(const T1& t1Data, const T2& t2Data) {} // This PrintNumbers(10, 100); // int, int PrintNumbers(14, 14.5); // int, double PrintNumbers(59.66, 150); // double, int // Can be changed to use this - and therefore limiting // the generated specialized versions to only double one PrintNumbers (10, 100); // int, int PrintNumbers (14, 14.5); // int, double PrintNumbers (59.66, 150); // double, int // Generated specialised version void PrintNumbers (const double& t1Data, const T2& t2Data) {}
или || класс в определении || шаблона ||. Ну, насколько я читал, это не имеет большого значения (особенно в C++20). До того, как использование было каким-то образом ограничено, когда || шаблоны шаблонов || были вызваны, Подробнее об этом || можно найти здесь || . я. Третья важная концепция заключается в том, что нет никакой причины, по которой в приведенном выше примере строка, использующая переменную ||short ||, с треском провалилась. прямое преобразование, когда мы используем || ТЕМ в нашем случае || шаблон || ожидает, что оба аргумента будут одинаковыми, чтобы преодолеть вышеуказанное ограничение, использовать || явный шаблон – это фактическая подсказка компилятору, какой будет тип этого метода также следует использовать, когда нет способа определить используемый тип из параметров конструктора или методов. Давайте взглянем на этот пример. e используемая переменная. (да, я знаю, длинное имя). спецификация аргумента te || Никаких исключений! тот же типаж, и все тут. тарелки или || класс в определении || шаблона ||. Ну, насколько я читал, это не имеет большого значения (особенно в C++20). До того, как использование было каким-то образом ограничено, когда || шаблоны шаблонов || были вызваны, Подробнее об этом || можно найти здесь || . я. Третья важная концепция заключается в том, что нет никакой причины, по которой в приведенном выше примере строка, использующая переменную ||short ||, с треском провалилась. прямое преобразование, когда мы используем || ТЕМ в нашем случае || шаблон || ожидает, что оба аргумента будут одинаковыми, чтобы преодолеть вышеуказанное ограничение, использовать || явный шаблон – это фактическая подсказка компилятору, каким будет тип этого метода. Также следует использовать, когда нет способа определить тип, используемый из параметров конструктора или Рассмотрите этот фрагмент кода: e методы. Давайте взглянем на этот пример. e используемая переменная. (да, я знаю, длинное имя). спецификация аргумента te || Никаких исключений! тот же типаж, и все тут. тарелки
templatevoid PrintSize() { cout << "Size of this type:" << sizeof(T); } // Calling it like this will cause compiler error PrintSize(); // But with this - it's working PrintSize ();
или класс в определении шаблона . Ну, насколько я читал, это не имеет большого значения (особенно в C++20). До того, как использование было каким-то образом ограничено, когда шаблоны шаблонов
или класс в определении шаблона
#includeusing namespace std; template T myMax(T x, T y) { cout << "Inside template implementation: "; return (x > y) ? x: y; } template<> short myMax(short x, short y) { cout << "Inside short implementation: "; return (x > y) ? x: y; } int main() { cout << myMax((short)3, (short)7 ) << "\n" << endl; // Call myMax for short cout << myMax(3, 7) << "\n" << endl; // Call myMax for int cout << myMax(3.0, 7.0) << "\n" << endl; // call myMax for double cout << myMax('g', 'e') << "\n" << endl; // call myMax for char return 0; }
или класс в определении шаблона . Ну, насколько я читал, это не имеет большого значения (особенно в C++20). До того, как использование было каким-то образом ограничено, когда шаблоны шаблонов
или || класс в определении || шаблона ||. Ну, насколько я читал, это не имеет большого значения (особенно в C++20). До того, как использование было каким-то образом ограничено, когда || шаблоны шаблонов || были инвоморированы, что || можно найти здесь ||. жил. Третья важная концепция заключается в том, что нет никакой причины, по которой в приведенном выше примере строка, использующая переменную ||short ||, с треском провалилась. явное преобразование, когда мы используем || ТЕМ в нашем случае || шаблон || ожидает, что оба аргумента будут одинаковыми, чтобы преодолеть вышеуказанное ограничение – использовать || явный шаблон. Это фактический намек компилятору, каким будет тип. Этот метод также следует использовать, когда нет способа определить тип, используемый из параметров конструктора или что в конце этого раздела стоит упомянуть, что есть возможность указать компилятору, какой сгенерированный метод следует вызывать. Описанная выше техника называется ||специализация|| и может быть применена к любому || шаблону функций ||. Взгляните на следующий код: Однако есть возможность предоставить нашу собственную реализацию этих функций, если мы захотим (что-то вроде методов по умолчанию в интерфейсах Java). || это используется в коде. Я упомянул в комментариях к приведенному выше коду, что компилятор создаст фактический код для каждого шаблона || функции, нет способа ограничить их видимость указанной областью. Возвращаясь к свойствам || шаблонов функций || – третье, что следует упомянуть, это то, что || шаблоны функций || могут быть помещены только в глобальное пространство имен. Рассмотрим этот фрагмент кода: e методы. Давайте взглянем на этот пример. e используемая переменная. (да, я знаю, длинное имя). спецификация аргумента te || Никаких исключений! тип пламени, и все. тарелки или || класс в определении || шаблона ||. Ну, насколько я читал, это не имеет большого значения (особенно в C++20). До того, как использование было каким-то образом ограничено, когда || шаблоны шаблонов || были инвоморированы, что || можно найти здесь ||. жил. Третья важная концепция заключается в том, что нет никакой причины, по которой в приведенном выше примере строка, использующая переменную ||short ||, с треском провалилась. прямое преобразование, когда мы используем || ТЕМ в нашем случае || шаблон || ожидает, что оба аргумента будут одинаковыми, чтобы преодолеть вышеуказанное ограничение, использовать || явный шаблон – это фактическая подсказка компилятору, какой будет тип этого метода также следует использовать, когда нет способа определить тип, используемый из параметров конструктора или я думаю, что следующий пример покажет, что я имею в виду. В конце этого раздела стоит упомянуть, что есть возможность указать компилятору, какой сгенерированный метод следует вызывать. Описанная выше техника называется ||специализация|| и может быть применена к любому || шаблону функций ||. Взгляните на следующий код: Однако есть возможность предоставить нашу собственную реализацию этих функций, если мы захотим (что-то вроде методов по умолчанию в интерфейсах Java). || это используется в коде. Я упомянул в комментариях к приведенному выше коду, что компилятор создаст фактический код для каждого шаблона || функции, нет способа ограничить их видимость указанной областью. Возвращаясь к свойствам || шаблонов функций || – третье, что следует упомянуть, это то, что || шаблоны функций || могут быть помещены только в глобальное пространство имен. Рассмотрим этот фрагмент кода: e методы. Давайте взглянем на этот пример. e используемая переменная. (да, я знаю, длинное имя). спецификация аргумента te || Никаких исключений! тип пламени, и все. тарелки
templateclass A { public: T x; U y; A() { cout<<"Constructor Called"< a; // This will call A return 0; }
или || класс в определении || шаблона ||. Ну, насколько я читал, это не имеет большого значения (особенно в C++20). До того, как использование было каким-то образом ограничено, когда || шаблоны шаблонов || были инвоморированы, что || можно найти здесь ||. жил. Третья важная концепция заключается в том, что нет никакой причины, по которой в приведенном выше примере строка, использующая переменную ||short ||, с треском провалилась. прямое преобразование, когда мы используем || ТЕМ в нашем случае || шаблон || ожидает, что оба аргумента будут одинаковыми, чтобы преодолеть вышеуказанное ограничение, использовать || явный шаблон – это фактическая подсказка компилятору, каким будет тип этого метода также следует использовать, когда нет способа определить тип, используемый из параметров конструктора или Вывод будет: Я думаю, что следующий пример покажет, что я имею в виду. В конце этого раздела стоит упомянуть, что есть возможность указать компилятору, какой сгенерированный метод следует вызывать. Описанная выше техника называется ||специализация|| и может быть применена к любому || шаблону функций ||. Взгляните на следующий код: Однако есть возможность предоставить нашу собственную реализацию этих функций, если мы захотим (что-то вроде методов по умолчанию в интерфейсах Java). || это используется в коде. Я упомянул в комментариях к приведенному выше коду, что компилятор создаст фактический код для каждого шаблона || функции, нет способа ограничить их видимость указанной областью. Возвращаясь к свойствам || шаблонов функций || – третье, что следует упомянуть, это то, что || шаблоны функций || могут быть помещены только в глобальное пространство имен. Рассмотрим этот фрагмент кода: e методы. Давайте взглянем на этот пример. e используемая переменная. (да, я знаю, длинное имя). спецификация аргумента te || Никаких исключений! тип пламени, и все. тарелки
Constructor Called
или || класс в определении || шаблона ||. Ну, насколько я читал, это не имеет большого значения (особенно в C++20). До того, как использование было каким-то образом ограничено, когда || шаблоны шаблонов || были инвоморированы, что || можно найти здесь ||. жил. Третья важная концепция заключается в том, что нет никакой причины, по которой в приведенном выше примере строка, использующая переменную ||short ||, с треском провалилась. явное преобразование, когда мы используем || ТЕМ в нашем случае || шаблон || ожидает, что оба аргумента будут одинаковыми, чтобы преодолеть вышеуказанное ограничение – использовать || явный шаблон. Это фактический намек компилятору, каким будет тип. Этот метод также следует использовать, когда нет способа определить тип, используемый из параметров конструктора или шаблонов классов. Вывод будет: Я думаю, что следующий пример покажет, что я имею в виду. В конце этого раздела стоит упомянуть, что есть возможность указать компилятору, какой сгенерированный метод следует вызывать. Описанная выше техника называется ||специализация|| и может быть применена к любому || шаблону функций ||. Взгляните на следующий код: Однако есть возможность предоставить нашу собственную реализацию этих функций, если мы захотим (что-то вроде методов по умолчанию в интерфейсах Java). || это используется в коде. Я упомянул в комментариях к приведенному выше коду, что компилятор создаст фактический код для каждого шаблона || функции, нет способа ограничить их видимость указанной областью. Возвращаясь к свойствам || шаблонов функций || – третье, что следует упомянуть, это то, что || шаблоны функций || могут быть помещены только в глобальное пространство имен. Рассмотрим этот фрагмент кода: e методы. Давайте взглянем на этот пример. e используемая переменная. (да, я знаю, длинное имя). спецификация аргумента te || Никаких исключений! тип пламени, и все. тарелки
или класс в определении шаблона . Ну, насколько я читал, это не имеет большого значения (особенно в C++20). До того, как использование было каким-то образом ограничено, когда шаблоны шаблонов были инвоморированы, что
#includeusing namespace std; template class MyClass { public: MyClass(T x, T y) { cout << "My class constructor: " + to_string(x) + " " + to_string(y) + "\n"; } T myMethodOutsideOfClass(); }; template T MyClass ::myMethodOutsideOfClass() { cout << "Inside short implementation \n"; return 0; } int main() { MyClass myClass(1,2); myClass.myMethodOutsideOfClass(); return 0; }
или класс в определении шаблона . Ну, насколько я читал, это не имеет большого значения (особенно в C++20). До того, как использование было каким-то образом ограничено, когда шаблоны шаблонов были инвоморированы, что можно найти здесь . жил. Третья важная концепция заключается в том, что нет никакой причины, по которой в приведенном выше примере строка, использующая переменную short , с треском провалилась. прямое преобразование, когда мы используем
или || класс в определении || шаблона ||. Ну, насколько я читал, это не имеет большого значения (особенно в C++20). До того, как использование было каким-то образом ограничено, когда || шаблоны шаблонов || были инвоморированы, что || можно найти здесь ||. жил. Третья важная концепция заключается в том, что нет никакой причины, по которой в приведенном выше примере строка, использующая переменную ||short ||, с треском провалилась. прямое преобразование, когда мы используем || ТЕМ в нашем случае || шаблон || ожидает, что оба аргумента будут одинаковыми, чтобы преодолеть вышеуказанное ограничение, заключается в использовании || явного шаблона. Это фактический намек компилятору, каким будет тип. Этот метод также следует использовать, когда нет способа определить тип, используемый из параметров конструктора или ththereодин улов в приведенном выше – реализация шаблона все еще должна быть доступна компилятору во время обработки заголовка! Проверьте || этот вопрос SO || для получения дополнительной информации. С четким разделением класса || объявление || от его || определения || – нам это не нужно. Если мы поместим всю логику внутри класса (в то время как он также служит интерфейсом), при каждом изменении в реализации нам придется перекомпилировать код. В C++ (и в C) существует целая концепция динамических/статических библиотек и возможность отделять интерфейс класса с помощью || заголовочных файлов || и использовать только их во время работы/написания кода. Однако, исходя из Java, мы привыкли к тому факту, что наши банки заполнены как интерфейсами, так и реализациями. Что ж, вы правы, так оно и есть. Это глупо и помещает логику класса в два разных места. Как специалисту по Java, мне было интересно – в чем причина определения функции вне класса? ПОДСКАЗКА! Вот пример: Единственное, что нам нужно сделать при реализации метода вне класса, – это добавить к функции имя класса. В качестве дополнительного момента существует возможность реализовать их в методах класса || вне || тела класса (этот метод применим также к определению “обычных” функций). Шаблоны классов || работают очень похоже на || шаблоны функций ||, хотя они определены на уровне класса (спасибо, Капитан Очевидность!). Шаблоны классов Результатом будет: Я думаю, что следующий пример покажет, что я имею в виду. В конце этого раздела стоит упомянуть, что есть возможность указать компилятору, какой сгенерированный метод следует вызывать. Описанная выше техника называется ||специализация|| и может быть применена к любому || шаблону функций ||. Взгляните на следующий код: Однако есть возможность предоставить нашу собственную реализацию этих функций, если мы захотим (что-то вроде методов по умолчанию в интерфейсах Java). || это используется в коде. Я упомянул в комментариях к приведенному выше коду, что компилятор создаст фактический код для каждого шаблона || функции, нет способа ограничить их видимость указанной областью. Возвращаясь к свойствам || шаблонов функций || – третье, что следует упомянуть, это то, что || шаблоны функций || могут быть помещены только в глобальное пространство имен. Рассмотрим этот фрагмент кода: e методы. Давайте взглянем на этот пример. e используемая переменная. (да, я знаю, длинное имя). спецификация аргумента te || Никаких исключений! тип пламени, и все. тарелки или || класс в определении || шаблона ||. Ну, насколько я читал, это не имеет большого значения (особенно в C++20). До того, как использование было каким-то образом ограничено, когда || шаблоны шаблонов || были инвоморированы, что || можно найти здесь ||. жил. Третья важная концепция заключается в том, что нет никакой причины, по которой в приведенном выше примере строка, использующая переменную ||short ||, с треском провалилась. прямое преобразование, когда мы используем || ТЕМ в нашем случае || шаблон || ожидает, что оба аргумента будут одинаковыми, чтобы преодолеть вышеуказанное ограничение, необходимо использовать || явный шаблон. Это фактический намек компилятору, каким будет тип. Этот метод также следует использовать, когда невозможно определить используемый тип из параметров конструктора или поэтому в проектах с несколькими файлами, если мы хотим предоставить заголовок с объявлением класса, все функции, использующие шаблон, также должны быть помещены в один файл! В приведенном выше есть одна загвоздка – реализация шаблона все еще должна быть доступна компилятору во время обработки заголовка! Проверьте || этот вопрос SO || для получения дополнительной информации. С четким разделением класса || объявление || от его || определения || – нам это не нужно. Если мы поместим всю логику внутри класса (в то время как он также служит интерфейсом), при каждом изменении в реализации нам придется перекомпилировать код. В C++ (и в C) существует целая концепция динамических/статических библиотек и возможность отделять интерфейс класса с помощью || заголовочных файлов || и использовать только их во время работы/написания кода. Однако, исходя из Java, мы привыкли к тому факту, что наши банки заполнены как интерфейсами, так и реализациями. Что ж, вы правы, так оно и есть. Это глупо и помещает логику класса в два разных места. Как специалисту по Java, мне было интересно – в чем причина определения функции вне класса? ПОДСКАЗКА! Вот пример: Единственное, что нам нужно сделать при реализации метода вне класса, – это добавить к функции имя класса. В качестве дополнительного момента существует возможность реализовать их в методах класса || вне || тела класса (этот метод применим также к определению “обычных” функций). Шаблоны классов || работают очень похоже на || шаблоны функций ||, хотя они определены на уровне класса (спасибо, Капитан Очевидность!). Шаблоны классов Результатом будет: Я думаю, что следующий пример покажет, что я имею в виду. В конце этого раздела стоит упомянуть, что есть возможность указать компилятору, какой сгенерированный метод следует вызывать. Описанная выше техника называется ||специализация|| и может быть применена к любому || шаблону функций ||. Взгляните на следующий код: Однако есть возможность предоставить нашу собственную реализацию этих функций, если мы захотим (что-то вроде методов по умолчанию в интерфейсах Java). || это используется в коде. Я упомянул в комментариях к приведенному выше коду, что компилятор создаст фактический код для каждого шаблона || функции, нет способа ограничить их видимость указанной областью. Возвращаясь к свойствам || шаблонов функций || – третье, что следует упомянуть, это то, что || шаблоны функций || могут быть помещены только в глобальное пространство имен. Рассмотрим этот фрагмент кода: e методы. Давайте взглянем на этот пример. e используемая переменная. (да, я знаю, длинное имя). спецификация аргумента te || Никаких исключений! тип пламени, и все. тарелки
или класс в определении шаблона . Ну, насколько я читал, это не имеет большого значения (особенно в C++20). До того, как использование было каким-то образом ограничено, когда шаблоны шаблонов были инвоморированы, что можно найти здесь . жил. Третья важная концепция заключается в том, что нет никакой причины, по которой в приведенном выше примере строка, использующая переменную short
#includeusing namespace std; template class MyClass { public: MyClass(T x, T y) { cout << "My class constructor: " + to_string(x) + " " + to_string(y) + "\n"; } template void myMethodOfClass(const U& arg) { cout << "Passed arg: " + to_string(arg) + "\n"; } }; int main() { MyClass myClass(1,2); myClass.myMethodOfClass(5); myClass.myMethodOfClass(2.0f); return 0; }
или класс в определении шаблона
#includeusing namespace std; template class Foo { public: void Func() {} }; template class Bar : public Foo { public: void BarFunc() { // Func(); This causes compilation error this->Func(); Foo ::Func(); } }; int main() { Bar b{}; b.BarFunc(); }
или || класс в определении || шаблона ||. Ну, насколько я читал, это не имеет большого значения (особенно в C++20). До того, как использование было каким-то образом ограничено, когда || шаблоны шаблонов || были инвоморированы, что || можно найти здесь ||. жил. Третья важная концепция заключается в том, что нет никакой причины, по которой в приведенном выше примере строка, использующая переменную ||short ||, с треском провалилась. прямое преобразование, когда мы используем || ТЕМ в нашем случае || шаблон || ожидает, что оба аргумента будут одинаковыми, чтобы преодолеть вышеуказанное ограничение – использовать || явный шаблон. Это фактическая подсказка компилятору, каким будет тип. Этот метод также следует использовать, когда нет способа определить тип, используемый из параметров конструктора или шаблонов thAlias, как обычно, вот код: Единственное ограничение здесь заключается в том, что мы должны явно указать компилятору, когда мы хотим использовать функциональность базового класса. В общем, нет никаких проблем с наследованием || шаблонов классов ||. Поскольку мы находимся на объектно-ориентированном языке (более или менее), мы также должны немного поговорить о наследовании. Я думаю, что код объяснит это лучше всего. (обратите внимание на слово ||метод||, а не ||функция ||). Существует также возможность ввести другое шаблонное решение, которое называется || шаблон метода || Когда дело доходит до || шаблонов классов ||, нам не нужно работать только на уровне класса. Вот почему в проектах с несколькими файлами, если мы хотим предоставить заголовок с объявлением класса, все функции, использующие шаблон, также должны быть помещены в один файл! В приведенном выше есть одна загвоздка – реализация шаблона все еще должна быть доступна компилятору во время обработки заголовка! Проверьте || этот вопрос SO || для получения дополнительной информации. С четким разделением класса || объявление || от его || определения || – нам это не нужно. Если мы поместим всю логику внутри класса (в то время как он также служит интерфейсом), при каждом изменении в реализации нам придется перекомпилировать код. В C++ (и в C) существует целая концепция динамических/статических библиотек и возможность отделять интерфейс класса с помощью || заголовочных файлов || и использовать только их во время работы/написания кода. Однако, исходя из Java, мы привыкли к тому факту, что наши банки заполнены как интерфейсами, так и реализациями. Что ж, вы правы, так оно и есть. Это глупо и помещает логику класса в два разных места. Как специалисту по Java, мне было интересно – в чем причина определения функции вне класса? ПОДСКАЗКА! Вот пример: Единственное, что нам нужно сделать при реализации метода вне класса, – это добавить к функции имя класса. В качестве дополнительного момента существует возможность реализовать их в методах класса || вне || тела класса (этот метод применим также к определению “обычных” функций). Шаблоны классов || работают очень похоже на || шаблоны функций ||, хотя они определены на уровне класса (спасибо, Капитан Очевидность!). Шаблоны классов Результатом будет: Я думаю, что следующий пример покажет, что я имею в виду. В конце этого раздела стоит упомянуть, что есть возможность указать компилятору, какой сгенерированный метод следует вызывать. Описанная выше техника называется ||специализация|| и может быть применена к любому || шаблону функций ||. Взгляните на следующий код: Однако есть возможность предоставить нашу собственную реализацию этих функций, если мы захотим (что-то вроде методов по умолчанию в интерфейсах Java). || это используется в коде. Я упомянул в комментариях к приведенному выше коду, что компилятор создаст фактический код для каждого шаблона || функции, нет способа ограничить их видимость указанной областью. Возвращаясь к свойствам || шаблонов функций || – третье, что следует упомянуть, это то, что || шаблоны функций || могут быть помещены только в глобальное пространство имен. Рассмотрим этот фрагмент кода: e методы. Давайте взглянем на этот пример. e используемая переменная. (да, я знаю, длинное имя). спецификация аргумента te || Никаких исключений! тип пламени, и все. тарелки
или класс в определении шаблона . Ну, насколько я читал, это не имеет большого значения (особенно в C++20). До того, как использование было каким-то образом ограничено, когда шаблоны шаблонов были инвоморированы, что можно найти здесь
templateclass Matrix { .... }; template using Square = Matrix ; // That's the alias template using Vector = Matrix ; // Code that uses above constructions Matrix ma; Square sq; Vector vec;
или класс в определении шаблона . Ну, насколько я читал, это не имеет большого значения (особенно в C++20). До того, как использование было каким-то образом ограничено, когда шаблоны шаблонов были инвоморированы, что можно найти здесь
или || класс в определении || шаблона ||. Ну, насколько я читал, это не имеет большого значения (особенно в C++20). До того, как использование было каким-то образом ограничено, когда || шаблоны шаблонов || были инвоморированы, что || можно найти здесь ||. жил. Третья важная концепция заключается в том, что нет никакой причины, по которой в приведенном выше примере строка, использующая переменную ||short ||, с треском провалилась. прямое преобразование, когда мы используем || ТЕМ в нашем случае || шаблон || ожидает, что оба аргумента будут одинаковыми, чтобы преодолеть вышеуказанное ограничение, заключается в использовании || явного шаблона. Это фактическая подсказка компилятору, каким будет тип. Этот метод также следует использовать, когда нет способа определить тип, используемый из параметров конструктора или переменных/переменных шаблонов. Он может быть применен к любому другому типу/определению! Идея ||сглаживания || связана не только с ||шаблонами ||! ПОДСКАЗКА! Решение является ясным и читабельным. Как обычно, лучший способ описать эту функциональность – с помощью простого фрагмента кода: Есть еще один способ, которым || шаблоны || могут быть полезны таким образом – || шаблоны псевдонимов Мы уже видели, что || шаблоны || являются отличным инструментом для уменьшения размера кода. Шаблоны псевдонимов Как обычно, вот код: Единственное ограничение здесь заключается в том, что мы должны явно указывать компилятору, когда мы хотим использовать функциональность базового класса. В общем, нет никаких проблем с наследованием || шаблонов классов ||. Поскольку мы находимся на объектно-ориентированном языке (более или менее), мы также должны немного поговорить о наследовании. Я думаю, что код объяснит это лучше всего. (обратите внимание на слово ||метод||, а не ||функция ||). Существует также возможность ввести другое шаблонное решение, которое называется || шаблон метода || Когда дело доходит до || шаблонов классов ||, нам не нужно работать только на уровне класса. Вот почему в проектах с несколькими файлами, если мы хотим предоставить заголовок с объявлением класса, все функции, использующие шаблон, также должны быть помещены в один файл! В приведенном выше есть одна загвоздка – реализация шаблона все еще должна быть доступна компилятору во время обработки заголовка! Проверьте || этот вопрос SO || для получения дополнительной информации. С четким разделением класса || объявление || от его || определения || – нам это не нужно. Если мы поместим всю логику внутри класса (в то время как он также служит интерфейсом), при каждом изменении в реализации нам придется перекомпилировать код. В C++ (и в C) существует целая концепция динамических/статических библиотек и возможность отделять интерфейс класса с помощью || заголовочных файлов || и использовать только их во время работы/написания кода. Однако, исходя из Java, мы привыкли к тому факту, что наши банки заполнены как интерфейсами, так и реализациями. Что ж, вы правы, так оно и есть. Это глупо и помещает логику класса в два разных места. Как специалисту по Java, мне было интересно – в чем причина определения функции вне класса? ПОДСКАЗКА! Вот пример: Единственное, что нам нужно сделать при реализации метода вне класса, – это добавить к функции имя класса. В качестве дополнительного момента существует возможность реализовать их в методах класса || вне || тела класса (этот метод применим также к определению “обычных” функций). Шаблоны классов || работают очень похоже на || шаблоны функций ||, хотя они определены на уровне класса (спасибо, Капитан Очевидность!). Шаблоны классов Результатом будет: Я думаю, что следующий пример покажет, что я имею в виду. В конце этого раздела стоит упомянуть, что есть возможность указать компилятору, какой сгенерированный метод следует вызывать. Описанная выше техника называется ||специализация|| и может быть применена к любому || шаблону функций ||. Взгляните на следующий код: Однако есть возможность предоставить нашу собственную реализацию этих функций, если мы захотим (что-то вроде методов по умолчанию в интерфейсах Java). || это используется в коде. Я упомянул в комментариях к приведенному выше коду, что компилятор создаст фактический код для каждого шаблона || функции, нет способа ограничить их видимость указанной областью. Возвращаясь к свойствам || шаблонов функций || – третье, что следует упомянуть, это то, что || шаблоны функций || могут быть помещены только в глобальное пространство имен. Рассмотрим этот фрагмент кода: e методы. Давайте взглянем на этот пример. e используемая переменная. (да, я знаю, длинное имя). спецификация аргумента te || Никаких исключений! тип пламени, и все. тарелки
или класс в определении шаблона . Ну, насколько я читал, это не имеет большого значения (особенно в C++20). До того, как использование было каким-то образом ограничено, когда шаблоны шаблонов были инвоморированы, что можно найти здесь . жил. Третья важная концепция заключается в том, что нет никакой причины, по которой в приведенном выше примере строка, использующая переменную short
// Args as a type/name is completely arbitrary and can be anything template// this is for the template void printMyParams(Args... args) // this is for the function
или класс в определении шаблона . Ну, насколько я читал, это не имеет большого значения (особенно в C++20). До того, как использование было каким-то образом ограничено, когда шаблоны шаблонов были инвоморированы, что можно найти здесь . жил. Третья важная концепция заключается в том, что нет никакой причины, по которой в приведенном выше примере строка, использующая переменную
#includetemplate T sum(T t, Args... args) { // [if constexpr] is evaluated during compile time // sizeof... is a special operator to determine the amount of params passed if constexpr(sizeof...(args) > 0) { return t + sum(args...); } return t; } int main() { std::cout << sum(1,2,3); }
или класс в определении
шаблона
#includetemplate T sum(T t) { return t; } template T sum(T t, Args... args) { return t + sum(args...); } int main() { std::cout << sum(1,2,3); }
Подводя итог презентации пакетов параметров , я покажу кое-что, что доступно начиная с C++17 – сворачивание (концепция известна из функциональных языков) – если вам интересно, вы можете прочитать об этом на официальной странице .
#includetemplate auto sum(Args... args) { return (... + args); } int main() { std::cout << sum(1,2,3); }
Члены статического шаблонного класса
Каждая функция или класс могут содержать статические члены. Следует задать широкий вопрос: как они ведут себя, когда используются в шаблонах? Ответ кроется в утверждении, представленном в предыдущем подразделе – шаблоны являются рецептом для создания определенных функций или классов. Следовательно, для каждой вычисляемой комбинации типов компилятор будет генерировать отдельный экземпляр функции/класса. Следовательно, каждый экземпляр будет иметь свой собственный закрытый статический член.
Понятия
В этой статье я просто упомяну их. Во-первых, потому что они заслуживают более описательной статьи, чем просто подраздел здесь. Второе – это новая функция, доступная в C++20. Поэтому он еще не получил широкого распространения. В общем – в Java мы пишем что-то вроде этого:
class MyClass() { T someOtherClass; }
На уровне компиляции мы проверяем, соответствует ли переданный объект критериям расширяет какой-либо другой класс . Это очень мощный инструмент, и именно поэтому C++ также представил его. Однако, как я уже сказал, позже я напишу отдельную статью и свяжу ее здесь.
источники:
- CppCon 2020 “Назад к основам – Шаблоны, часть 1” обсуждение
- CppCon 2020 “Назад к основам – Шаблоны, часть 2” обсуждение
- Вернемся к основам: Шаблоны функций и классов – Дэн Сакс – CppCon 2019
- Бьярне Страуструп |/”Принципы программирования и практика использования C++ 2ed” книга Джош Лоспиносо
- |/”Ускоренный курс C++” книга Шаблоны в C++ против дженериков в Java статья
- Имя типа против класса Параметры шаблонов и шаблоны псевдонимов
- Руководство по шаблонам C++
- Constэкспр если объяснено
- Пакет параметров
От Java до C++ (Серия из 2 частей)
Оригинал: “https://dev.to/chlebik/from-java-to-c-templates-5hf3”