Как определяется неоднозначность в алгоритме разрешения перегрузки?
Я пытаюсь понять метод разрешения перегрузки.
почему это неоднозначная:
void func(double, int, int, double) {}
void func(int, double, double, double) {}
void main()
{
func(1, 2, 3, 4);
}
но это не?
void func(int, int, int, double) {}
void func(int, double, double, double) {}
void main()
{
func(1, 2, 3, 4);
}
в первом случае есть 2 точных совпадения параметров и 2 преобразования против 1 точного совпадения и 3 преобразования, а во втором случае есть 3 точных совпадения и 1 преобразование против 1 точного совпадения и 3 преобразования.
Так почему же один неоднозначен, а другой нет? В чем тут логика?
3 ответа:
правила разрешения перегрузки определяют только частичный порядок на множестве всех совпадений-если перегрузка
F1
не лучший матч, чемF2
, это не означает, чтоF2
Это лучший матч, чемF1
. Точный частичный порядок можно рассматривать как сравнение двух точек вk
размеры, где число аргументовk
. Давайте определим этот частичный порядок по точкам вk
-Дим пространства -(x_1, x_2,..., x_k) < (y_1, y_2,..., y_k) if x_i <= y_i for all i and x_j < y_j for at least one j
. Это именно частичный порядок на кандидате без шаблона функции, определенные стандартом.давайте посмотрим на ваши примеры :
void func(double, int, int, double) {} vvv vvv vvv better better equal void func(int, double, double, double) {} vvv vvv better equal
таким образом, ни одна перегрузка не является строго лучше, чем другая.
второй пример:
void func(int, int, int, double) {} vvv vvv vvv vvv equal better better equal void func(int, double, double, double) {} vvv equal
Итак, первая перегрузка лучше второй во всех аргументах, кроме одного, и никогда не хуже второй. Таким образом, нет никакой двусмысленности - частичный порядок действительно объявляет первый лучше.
(приведенное выше описание не рассмотрим шаблоны функций. Вы можете найти более подробную информацию на cppreference.)
формулировка из стандарта (§[over.спичка.best] / 1) это:
[...] пусть ICSЯ(F) обозначает неявную последовательность преобразования, которая преобразует Я-й аргумент в списке к типу Я - й параметр жизнеспособной функции F.
[...] жизнеспособная функция F1 определяется как лучшая функция, чем другая жизнеспособная функция F2, если для всех аргументов Я, ICSЯ(F1) не хуже преобразования последовательности, чем ICSЯ(F2), а затем
- для некоторых аргумент j, ICSj(F1) является лучшей последовательностью преобразования, чем ICSj(F2)в вашем первом случае две функции не проходят первый тест. Для первого аргумента, первая функция (принимая
double
) имеет худшую последовательность преобразования, чем вторая. Для второго аргумента вторая функция имеет худшую последовательность преобразования, чем первая (опять же,int
есть чтобы быть повышен доdouble
в одном случае, но не в других).поэтому ни одна из функций не передает первое правило, и вызов неоднозначен.
между второй парой функций каждый аргумент первой функции имеет по крайней мере такое же хорошее преобразование, как и соответствующий аргумент второй функции. Затем мы переходим ко второму правилу и обнаруживаем, что существует по крайней мере один аргумент (два, по сути), для которого первая функция имеет лучшее преобразование (идентичность вместо продвижения), чем второй.
поэтому первая функция является лучшим соответствием и будет выбрана.
неоднозначность определяется ранжированием:
- точное соответствие: не требуется преобразование, преобразование lvalue в rvalue, преобразование квалификации, пользовательское преобразование типа класса в тот же класс
- промотирование: объединенное промотирование, промотирование с плавающей запятой
- преобразование: интегральное преобразование, преобразование с плавающей запятой, преобразование с плавающей запятой, преобразование указателя, преобразование указателя в элемент, булево преобразование, определяемое пользователем преобразование производного класса в его базу
точное совпадение выигрывает против продвижения, которое выигрывает против преобразования.
пример:
void func(int, bool, float, int){cout << "int,bool,float,int" << endl;} void func(int, bool, int, int){cout << "int,int,int,int" << endl;} int main() { func(1,1,3.4,4); }