Благодаря частичному упорядочению шаблонов функций следующее представляется однозначным:
template <class T> void f(T*) {
cout << "T*" << endl;
}
template <class T> void f(const T*) {
cout << "const T*" << endl;
}
int main(){
int *p = nullptr;
f(p);
}
T
выводится как int
в обоих случаях, и обе специализации являются жизнеспособными со вторым требованиемнеявное преобразование квалификации из int *
в const int*
.Оба добавляются в набор перегрузки.
Чтобы найти наилучшую жизнеспособную функцию, мы переходим к частичному упорядочению.Мы синтезируем новые типы для каждого и получаем void f(X*)
и void f(const Y*)
.Затем мы делаем вывод типа между двумя.[temp.deduct.partial] ¶8:
Используя результирующие типы P и A, затем производится вычет, как описано в 17.8.2.5.(...) Если для данного типа вывод выполняется успешно, считается, что тип из шаблона аргумента, по крайней мере, такой же специализированный, как и тип из шаблона параметра.
Успешен ли вывод для template <class T> void f(T*)
дано const Y*
?Да, с T=const Y
.
Успешен ли вычет для template <class T> void f(const T*)
при X*
?Да, с T=X
(требующим неявного преобразования квалификации).
Таким образом, X и Y, по крайней мере, столь же специализированы, как и другие, что означает, что обе специализации, по крайней мере, столь же специализированы, как и другая, что означаетчто вызов неоднозначен.
За исключением того, что это не так, так где я ошибся выше?