Pull to refresh

Перегрузка и специализация. Тонкий момент

Reading time 2 min
Views 20K
В сегодняшней краткой заметке я опишу тонкий момент связанный с перегрузкой и специализацией функций. Не так давно встретилось на практике и появился повод проапдейтить запись в личной БД на эту тему. Этой информацией и поделюсь.

Пример


template<typename T> void foo(T);  // 1
template<> void foo(int*);         // 2
template<typename T> void foo(T*); // 3

template<typename T> void bar(T);  // 4
template<typename T> void bar(T*); // 5
template<> void bar(int*);         // 6

void f() {
	int i;
	foo(&i);
	bar(&i);
}

Итак у нас есть 2 абсолютно одинаковых набора функций, однако, как вы понимаете, без подвоха тут не обойдется. Какие именно из них будут вызваны?

Объяснение


Те кто ответил 3 и 6 могут сегодня потратить на торчание на хабре на полчаса больше рабочего времени чем обычно. Чтобы объяснить такое поведение нужно вспомнить какие существуют категории функций с точки зрения перегрузки.

1. Обычные функции;
2. базовые шаблоны. Это функции вида
template<typename T> void bar(T);

3. Специализации шаблонов функций.

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

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

То есть в примере выше (2) является специализацией не (3) а (1), поэтому для перегрузки будет выбран более подходящий базовый шаблон (3). Во втором же случае (6) является специализацией (5), которая в свою очередь является лучшей кандидатурой, чем (4).
Tags:
Hubs:
+26
Comments 19
Comments Comments 19

Articles