Хабрахабр

Основы шаблонов С++: шаблоны функций

Тема очень обширна, поэтому публикуется в урезаном виде. Дисклаймер: статья была начата еще в феврале, но, по зависящим от меня причинам, закончена не была. Что не поместилось, будет рассмотренно позже.

Данное свойство языка открывает широкие возможности оптимизации и повторного использования кода. Невозможно разбираться в современном С++, не зная, что такое шаблоны программирования. В данной статье попробуем разобраться, что это такое и как это всё работает.

Например, алгоритм сортировки может работать как с целыми числами, так и с объектами типа «автомобиль».
Существуют шаблоны функций и шаблоны классов. Механизм шаблонов в языке С++ позволяет решать проблему унификации алгоритма для различных типов: нет необходимости писать различные функции для целочисленных, действительных или пользовательских типов – достаточно составить обобщенный алгоритм, не зависящий от типа данных, основывающийся только на общих свойствах.

По описанию шаблон функции похож на обычную функцию: разница в том, что некоторые элементы не определены (типы, константы) и являются параметризованными. Шаблоны функций -– это обобщенное описание поведения функций, которые могут вызываться для объектов разных типов. Другими словами, шаблон функции (шаблонная функция, обобщённая функция) представляет собой семейство разных функций (или описание алгоритма).

Шаблоны классов -– обобщенное описание пользовательского типа, в котором могут быть параметризованы атрибуты и операции типа. Представляют собой конструкции, по которым могут сгенерированы действительные классы путём подстановки вместо параметров конкретных аргументов.

Рассмотрим более подробно шаблоны функций.

Шаблоны функций

Как написать первую шаблонную функцию?

Рассмотрим случай определения минимального элемента из двух. В случае целых и действительных чисел придется написать 2 функции.

int _min(int a, int b) return b;
} double _min(double a, double b){ if( a < b){ return a; } return b;
}

Можно, конечно, реализовать только одну функцию, с действительными параметрами, но для понимания шаблонов это будет вредным.

Что произойдёт в случае компиляции приложения? Обе реализации функции попадут в бинарный код приложения, даже если они не используются (впрочем, сейчас компиляторы очень умные, умеют вырезать неиспользуемый код). А если необходимо добавить функцию, определяющую минимальную из 2 строк (сложно представить без уточнения что есть минимальная строка)?!

Принцип, в общем случае, будет следующим: В этом случае, если алгоритм является общим для типов, с которыми приходится работать, можно определить шаблон функции.

  1. берётся реализация функции для какого-то типа;
  2. приписывается заголовок template<class Type> (или template<typename Type>), что означает, что в алгоритме используется какой-то абстрактный тип Type;
  3. в реализации функции имя типа заменяется на Type.

Для функции min получится следующее:

template<class Type>
Type _min(Type a, Type b){ if( a < b){ return a; } return b;
}

Самым интересным является тот факт, что пока нет вызова функции min, при компиляции она в бинарном коде не создается (не инстанцируется). А если объявить группу вызовов функции с переменными различных типов, то для каждого компилятор создаст свою реализацию на основе шаблона.

В этом случае компилятор определит, какой тип использовать вместо Type на основании типа фактических параметров. Вызов шаблонной функции, в общем, эквивалентен вызову обыкновенной функции. Так, в ниже следующем коде компилятор споткнётся на третьем вызове, так как не может определить, чему равен Type (подумайте, почему?): Но если параметры окажутся разных типов, то компилятор не сможет вывести (инстанцировать шаблон) реализацию шаблона.

#include <iostream>
template<class Type>
Type _min(Type a, Type b) { if (a < b) { return a; } return b;
} int main(int argc, char** argv) { std::cout << _min(1, 2) << std::endl; std::cout << _min(3.1, 1.2) << std::endl; std::cout << _min(5, 2.1) << std::endl; // oops! return 0;
}

Решается эта проблема указанием конкретного типа при вызове функции.

#include <iostream>
template<class Type>
Type _min(Type a, Type b) { if (a < b) { return a; } return b;
} int main(int argc, char** argv) { std::cout << _min<double>(5, 2.1) << std::endl; return 0;
}

Когда шаблонная функция (не) будет работать?

В принципе, можно понять, что компилятор просто подставляет нужный тип в шаблон. Но всегда ли получаемая функция будет работоспособна? Очевидно, что нет. Любой алгоритм может быть определен независимо от типа данных, но он обязательно пользуется свойствами этих данных. В случае с шаблонной функцией _min это требование определения оператора упорядочения (оператор

В ожидаемом стандарте языка С++ за это будут отвечать концепции. Любой шаблон функции предполагает наличие определенных свойств параметризованного типа, в зависимости от реализации (например, оператора копирования, оператора сравнения, наличия определенного метода и т.д.).

Перегрузка шаблона функции

Шаблоны функций также могут перегружатся. Обычно данная перегрузка выполняется при

template<class Type>
Type* _min(Type* a, Type* b){ if(*a < *b){ return a; } return b;
}

Частные случаи

В некоторых случаях шаблон функции является неэффективным или неправильным для определенного типа. В этом случае можно специализировать шаблон, — то есть написать реализацию для данного типа. Например, в случае со строками, можно потребовать, чтобы функция сравнивала только количество символов. В случае специализации шаблона функции, тип, для которого уточняется шаблон в параметре не указывается. Ниже приводится пример указанной специализации.

template<>
std::string _min(std::string a, std::string b){ if(a.size() < b.size()){ return a; } return b;
}

Специализация шаблона для конкретных типов делается опять же из соображения экономичности: если эта версия шаблона функции в коде не используется, то она не будет включена в байткод.

Естественным продолжением являются шаблоны классов, основы порождающего программирования, и устройство стандартной библиотеки С++. На будущее остаются множественные и целочисленные параметры. И куча примеров!

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»