Шаблонный код, boilerplate-код () — нетворческий программный код, который программисту приходится писать вследствие требований языка программирования, операционной системы, библиотеки подпрограмм, манеры программирования и прочего. Название «шаблонный» говорит, что он повторяется из функции в функцию, из программы в программу с минимальными изменениями. Шаблонными, в числе прочего, будут: подключение модулей; настройка компилятора и/или системы сборки; организация точки входа в программу или подпрограмму; код инициализации и выхода; идиомы языка.

Например, в простейшем «Hello, world» на Си все строки, кроме собственно printf(...), будут шаблонными. #include <stdio.h> //< шаблонный — подключение модуля int main() //< шаблонный — точка входа { //< шаблонный — точка входа printf("Hello, world!\n"); //< творческий!! return 0; //< шаблонный — выход } //< шаблонный — точка входа

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

Этимология понятия «boilerplate» Слово «boilerplate» по-английски означает «котельное железо». Применительно к шаблонному тексту встречается уже в 1950-х. Этимология неясна и определённо происходит из лексикона полиграфистов, основные версии: Местные американские газеты подписывались на получение новостей у крупных печатных синдикатов, и те присылали их в виде готовых заметок на отлитых печатных формах. Эти формы и называли «котельным железом». Печатные формы, которые нужны были многократно в нескольких выпусках газеты — для газетных шапок, объявлений от постоянных клиентов и т. д. — делали из стали, в то время как основная часть газеты набиралась из свинцового сплаваWhy is it «Boilerplate text?» | Mental Floss. Дымогарный котёл требовал сверления множества отверстий, в которые вставляли дымогарные трубы. Для сверления использовали пластины-шаблоны, и написание стандартных объявлений сравнили с шаблонным сверлением отверстийWhat is the origin of the term 'boilerplate'? — Quora.

Методы уменьшения количества шаблонного кода

Системы и библиотеки, решающие вопрос Стандартный код на Java: public class Book { private String m_ISBN; private String m_Title; private String m_SubTitle; private String m_Autor;

public String getISBN() { return m_ISBN; } public void setISBN(String pISBN) { m_ISBN = pISBN; }

public String getTitle() { return m_Title; } public void setTitle(String pTitle) { m_Title = pTitle; }

public String getSubTitle() { return m_SubTitle; } public void setSubTitle(String pSubTitle) { m_SubTitle = pSubTitle; }

public String getAutor() { return m_Autor; } public void setAutor(String pAutor) { m_Autor = pAutor; } }

Аналогичный код на C#… public class Book { public string ISBN { get; set; } public string Title { get; set; } public string SubTitle { get; set; } public string Autor { get; set; } }

…и на Kotlin data class Book(var ISBN: String, var Title: String, var SubTitle: String, var Autor: String)

Стоит сказать, что языки программирования стараются избавляться от шаблонного кода. Примером может быть 17 версия Java, в которой появился специальный тип record, позволяющий писать меньше кода, подобно Kotlin public record Book(String m_ISBN, String m_Title, String m_SubTitle, String m_Autor) { }

Автогенераторы кода Например, в системе Qt Widgets код минимальной формы с кнопкой состоит из нескольких файлов, приведём один. //== FmMain.cpp == #include "FmMain.h" #include "ui_FmMain.h"

FmMain::FmMain(QWidget *parent) : QMainWindow(parent) , ui(new Ui::FmMain) { ui->setupUi(this); }

FmMain::~FmMain() { delete ui; }

void FmMain::on_btDemo_clicked() { ui->btDemo->setText("Demo!!"); //< Только эту строку мы пишем вручную! }

При этом только одну строку программист пишет вручную.

Адекватные настройки по умолчанию Пример 1. В Qt+MinGW для создания автономной консольной программы под Windows надо сделать: win32-g++ { QMAKE_CXXFLAGS += -static-libgcc -static-libstdc++ LIBS += -static -lpthread }

Это также считается шаблонным кодом. Поскольку мелкие учебные и экспериментальные программы обычно являются автономными и консольными, возможно, следовало бы добавлять подобный код всегда при создании пустой консольной программы — а разработчик более сложного ПО, использующего чужие динамические библиотеки, просто стирал бы его.

Пример 2. Полный HTML выглядит так: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"/> <title>Test</title> </head> <body> <p>Hello world!</p> </body> </html> Стандарт WHATWG HTML позволяет опустить html, head и body. Meta charset можно опустить, если HTML пришёл от сервера и в заголовках HTTP есть кодировка. Так что остаётся… <!DOCTYPE html> <title>Test</title> <p>Hello world!</p>

Препроцессоры Пример 1. В том же Qt есть две программы, создающие часть Си++-кода формы — метаобъектный компилятор (moc) и компилятор интерфейса (uic).

Пример 2. Создание копии объекта с учётом умных указателей Си++11 выглядит так. #include <iostream> #include <memory>

class Abstract { public: auto clone() const { return std::unique_ptr<Abstract>{ vclone() }; } protected: virtual Abstract* vclone() const = 0;

class Abstract2 : public Abstract { public: auto clone() const { return std::unique_ptr<Abstract2>{ vclone() }; } protected: virtual Abstract2* vclone() const = 0;

class Concrete : public Abstract2 { public: auto clone() const { return std::unique_ptr<Concrete>{ vclone() }; } protected: Concrete* vclone() const override { return new Concrete(*this); }

int main() { Concrete impl;

Abstract* a = &impl; std::unique_ptr<Abstract> b = a->clone(); std::unique_ptr<Concrete> c = impl.clone();

return 0; } Здесь шаблонный код — реализации функций и .

С препроцессором Си этот код будет выглядеть так, и чем больше классов в иерархии, тем больше выигрыш: #define IMPL_CLONE_1(Class, Body) \ public: auto clone() const { return std::unique_ptr<Class>{ vclone() }; } \ protected: virtual Class* vclone() const Body

#define IMPL_CLONE_ABSTRACT(Class) IMPL_CLONE_1(Class, override = 0;) #define IMPL_CLONE_CONCRETE(Class) IMPL_CLONE_1(Class, override { return new Class(*this); })

class Abstract { IMPL_CLONE_1(Abstract, =0;)

class Abstract2 : public Abstract { IMPL_CLONE_ABSTRACT(Abstract2)

class Concrete : public Abstract2 { IMPL_CLONE_CONCRETE(Concrete)

Метапрограммирование На Си++ обрезка пробелов (trim) в строках разного типа «на месте» (без выделения памяти) будет выглядеть так: std::string_view trimSv(std::string_view x) { // Какая-то реализация }

std::wstring_view trimSv(std::wstring_view x) { // Похожая реализация }

И то же с метапрограммированием: namespace detail { template <class Ch, class Traits> std::basic_string_view<Ch, Traits> trimSv(std::basic_string_view<Ch, Traits> x) { // Реализация

template <class S> inline auto trimSv(const S& x) { return detail::trimSv(static_cast<std::basic_string_view>(x)); }

Код также многословный (вторая функция нужна, чтобы под шаблон подходил не только std::string_view, но и близкие к нему типы std::string и const char*), но как минимум без повторов.

Си++23 решает задачу с созданием копии метапрограммированием, через this-параметры. В коде есть ловушка: невозможно создать точное копирование одним только шаблоном, виртуальный всё равно нужен — иначе произойдёт непреднамеренное присваивание в базовый тип. class Abstract { public: template <class Self> auto clone(this const Self& me)

using CleanSelf = std::decay<Self>; return std::unique_ptr<CleanSelf>{ me.vclone() };

Примечания

Категория:Исходный код