#новичкам
Давайте немного разбавим рассказ о фичах 23-го стандарта чем-нибудь более приземленным
Мы знаем, что шаблоны используются как лекарство от повторения кода, а также как средство реализации полиморфизма времени компиляции. Но неужели без них нельзя обойтись?
Можно и обойтись. Возьмем хрестоматийный пример std::qsort. Это скоммунизденная реализация сишной стандартной функции qsort. Сигнатура у нее такая:
void qsort( void *ptr, std::size_t count, std::size_t size, /* c-compare-pred */* comp );
extern "C" using /* c-compare-pred */ = int(const void*, const void*);
extern "C++" using /* compare-pred */ = int(const void*, const void*);
Как видите, здесь много
void * указателей на void. В том числе с помощью него достигается полиморфизм в С(есть еще макросы, но не будем о них).Как это работает?
Функция qsort спроектирована так, чтобы с ее помощью можно было сортировать любые POD типы. Но не хочется как-то пеерегружать функцию сортировки для всех потенциальных типов. Поэтому придумали обход. Передавать void указатель, чтобы мочь обрабатывать данные любых типов. Но void* - это нетипизированный указатель, поэтому фунции нужно знать размер типа данных, которые она сортирует, и количество данных. А также предикат сравнения.
Вот тут немного поподробнее. Предикат для интов может выглядеть примерно так:
[](const void* x, const void* y)
{
const int arg1 = *static_cast<const int*>(x);
const int arg2 = *static_cast<const int*>(y);
const auto cmp = arg1 <=> arg2;
if (cmp < 0)
return -1;
if (cmp > 0)
return 1;
return 0;
}
Предикату не нужно передавать размер типа, потому что он сам знает наперед с каким данными он работает и сможет закастить void* к нужному типу.
Вот в этом предикате и проблема. Функция qsort не знает на этапе компиляции, с каким предикатом она будет работать. Поэтому компилятор очень ограничен в оптимизации этой части: он не может заинлайнить код компаратора в код qsort. На каждый вызов компаратора будет прыжок по указателю функции. Это примерна та же причина, по которой виртуальные вызовы дорогие.
Тип шаблонных параметров, напротив, известен на этапе компиляции.
template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );
Значит код компаратора шаблонной функции может быть включен в код сортировки. Именно поэтому функция std::sort намного быстрее std::qsort при включенных оптимизациях(а без них примерно одинаково)
Казалось бы плюсы, а быстрее сишки. И такое бывает, когда используешь шаблоны.
Use advanced technics. Stay cool.
#template #goodoldc #goodpractice #compiler