перегрузка шаблона функции
может ли кто-нибудь обобщить идею перегрузки шаблона функции? Что имеет значение, параметр шаблона или параметр функции? Как насчет возвращаемого значения?
например, учитывая шаблон функции
template<typename X, typename Y> void func(X x, Y y) {}
что такое перегруженный шаблон функции?
1) template<typename X> void func(X x, int y) {}
2) template<typename X, typename Y> X func(X x, Y y) {}
3) template<class X, class Y, class Z> void func(X x, Y y, Z z) {}
4 ответов
из этого списка только второй вводит двусмысленность, потому что функции - независимо от того, шаблоны - не могут быть перегружены на основе возвращаемого типа.
вы можете использовать два других:
template<typename X> void func(X x, int y);
будет использоваться, если второй аргумент вызова является int, e.g func("string", 10);
template<class X, class Y, class Z> void func(X x, Y y, Z z);
будет использоваться, если вы вызываете func с тремя аргументами.
Я не понимаю, почему в некоторых других ответах упоминается, что функции шаблона и перегрузка функций не смешивается. Они, конечно, делают, и есть специальные правила, как выбрана функция для вызова.
14.5.5
шаблон функции может быть перегружен другой функцией шаблоны и с нормальным (не шаблонные) функции. Нормаль функция не связана с шаблон функции (т. е. никогда считается специализацией), даже если он имеет то же имя и тип как потенциально производящая функция специализация шаблона.)
не шаблонная (или "менее шаблонная") перегрузка предпочтительнее шаблонов, e.g
template <class T> void foo(T);
void foo(int);
foo(10); //calls void foo(int)
foo(10u); //calls void foo(T) with T = unsigned
ваша первая перегрузка с одним параметром без шаблона также подпадает под это правило.
учитывая выбор между несколькими шаблонами, более специализированные матчи предпочтительны:
template <class T> void foo(T);
template <class T> void foo(T*);
int i;
int* p;
int arr[10];
foo(i); //calls first
foo(p); //calls second
foo(arr); //calls second: array decays to pointer
вы можете найти более формальное описание всех правил в той же главе стандарта (
здесь есть две отдельные вещи: шаблон функций и перегрузка функций. Любые два различных объявления шаблона, вероятно, будут перегружены друг другом, поэтому ваш вопрос не совсем имеет смысл, как указано. (Три" перегрузки", которые вы даете, не строятся на первом шаблоне, скорее у вас есть четыре перегрузки с тем же именем функции.) Реальная проблема заключается в том, учитывая некоторые перегрузки , а вызов, как вызвать желаемую перегрузку?
во-первых, тип вернуться не участвует в процессе перегрузки, независимо от того, задействован ли шаблон. Так что #2 никогда не будет хорошо играть с #1.
во-вторых, правила разрешения перегрузки шаблонов функций отличаются от более часто используемых правил специализации шаблонов классов. Оба по существу решают одну и ту же проблему, но
- правила для шаблонов классов проще и мощнее, позволяя, например, рекурсию и (член) функции, отличающиеся только возвращением тип
- правила для шаблонов функций позволяют компилятору вычислять аргументы шаблона из типов аргументов функции
вы можете решить свою конкретную проблему с перегрузками шаблона функции, но у вас могут возникнуть проблемы с исправлением любой ошибки, которая возникает, поскольку правила длиннее и меньше людей знакомы с их тонкостями. Я не знал после нескольких лет взлома шаблонов, что тонкая перегрузка шаблонов функций была даже возможна. В библиотеки, такие как Boost и STL GCC, альтернативный подход вездесущ. Используйте шаблонный класс-оболочку:
template< typename X, typename Y >
struct functor {
void operator()( X x, Y y );
};
template< typename X > // partial specialization:
struct functor< X, int > { // alternative to overloading for classes
void operator()( X x, int y );
};
теперь вы жертвуете неявным синтаксисом экземпляра (без угловых скобок). Если вы хотите получить это обратно, вам нужна другая функция
template< typename X, typename Y > void func( X x, Y y ) {
return functor< X, Y >()( x, y );
}
мне было бы интересно узнать, может ли перегрузка функций делать что-либо (кроме вычета), что специализация класса [частичная] не может...
и тогда, конечно, ваша перегрузка #3 никогда не столкнитесь с неоднозначностью, потому что она имеет другое количество аргументов, чем любая другая перегрузка.
помимо комментариев, еще немного информации по теме в статье травы Саттеров это Почему Бы Не Специализировать Шаблоны Функций. Надеюсь, это тоже поможет.
Я исправлен-см. комментарии ниже. Я не буду изменять ни один из моих оригинальных сообщений, так как это удалит контекст ответов. Я благодарю комментаторов за их вклад и за то, что они не проголосовали за меня
считайте, что шаблоны похожи на макропроцессор, который расширяет #defines до того, как компилятор их увидит.
компилятор "развернет" ваши параметры шаблона, а затем посмотрит на ваши объявления функций. Так, параметр шаблона = = параметр функции. Если вы объявите одну и ту же функцию дважды, вы получите ошибку.
вы спрашиваете о типе возврата. Это часть "подписи" функции. Две функции с одинаковыми параметрами, но различными типами возврата-это две разные функции.