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

Понятие шаблона функций

Шаблоном функций называют общее описание семейства функций (обобщенного алгоритма ). Об этом уже было сказано, но рассмотрим их поподробней.

find:min:int.cpp
int min(int a, int b){
  int result = a;
  if(b < a) {
    result = b;
  }
  return result;
}

Если нам понадобится поиск минимального целого числа, то можно воспользоваться функцией, представленной в листинге find_min_int.cpp. Однако, для поиска минимума среди действительных чисел придется в программу добавить функцию из листинга find_min_float.cpp:

find_min_float.cpp
float min(float a, float b){
  float result = a;
  if(b < a) {
    result = b;
  }
  return result;
}

Таким образом, для каждого типа приходится переопределять функцию.

Однако, для каждого типа данных функция выглядит одинаково. В связи с чем язык С++ предлагает механизм шаблонов, который позволяет описать семейство функций. Пример соответсвующего шаблона приведен в листинге find_min_tpl.cpp.

find_min_tpl.cpp
template<typename TYPE>
TYPE min(TYPE a, TYPE b){
  TYPE result = a;
  if(b < a) {
    result = b;
  }
  return result;
}

Определение шаблона начинается с ключевой конструкции template<typename TYPE, ...> где в угловых скобках указываются параметры шаблона. Параметров шаблона может быть любое количество, в качестве параметра может быть тип или перечислимое значение.

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

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

min_inst.cpp
#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; // OK
    std::cout << min(3.1, 1.2) << std::endl; // OK
    std::cout << min(5, 2.1) << std::endl; // error! can`t deduce from template!
    return 0;
}

Эту проблему можно решить явным указанием подставляемого в шаблон типа.

min_inst_2.cpp
#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; // OK
    std::cout << min(3.1, 1.2) << std::endl; // OK
    std::cout << min<double>(5, 2.1) << std::endl; // OK
    return 0;
}

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

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

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

Last updated