Здравствуйте, Vain, Вы писали:
К>>Здравым смыслом, как ещё. g(T,char)[T=char] подходит лучше, чем g(char,long), потому что не требует приведения типа. К>>А вот если бы было ещё g(char,char), то g(T,char)[T=char] будет хуже, потому что требует подстановки. V>Т.е. по логике компилятор должен выбирать более детальную инстанцию функции уже после инстанцирования?
Нет. SFINAE распространяется только на объявление.
Облом инстанцирования уже считается ошибкой.
Что касается предпочтений g('a','a') из g<T>(T,T), g<T>(T,char), g(char,char) — как раз из-за того, что компилятор считает, что g<T>(T,T) и g<T>(T,char) одинаково удалены от искомого, (там и возникает ошибка неоднозначности).
"Более специализировано" было бы g<T>(T,T) или g<T>(T,char) перед g<T,U>(T,U)
Только не проси меня лазать в стандрат сейчас — вечер, голова пухнет...
Естественно, компилятор ведёт два списка — сигнатуры конкретных функций и шаблоны функций.
Причём, несколько разных шаблонов могут инстанцироваться к одной и той же сигнатуре. Но для этого надо особым образом постараться.
...
f<char,char>(x,x); // T,U T=char,U=char
f<int>(x,c); // T,char T=int
f<int>(c,x); // T,T T=int
f<int>(c,c); // T,char T=int - вот здесь я затрудняюсь объяснить, почему так.
}
Здравствуйте, Кодт, Вы писали:
К>>>Здравым смыслом, как ещё. g(T,char)[T=char] подходит лучше, чем g(char,long), потому что не требует приведения типа. К>>>А вот если бы было ещё g(char,char), то g(T,char)[T=char] будет хуже, потому что требует подстановки. V>>Т.е. по логике компилятор должен выбирать более детальную инстанцию функции уже после инстанцирования? К>Нет. SFINAE распространяется только на объявление.
Так и есть, это можно проверить даже:
#include <stdio.h>
template<class T>
void g(T,T)
{
static int a[sizeof(T)-sizeof(T) ? 1 : -1];
printf("1\n");
}
template<class T>
void g(T,char)
{
static int a[sizeof(T)-sizeof(T) ? 1 : -1];
printf("2\n");
}
int main()
{
g('a','1'); //1 error, not 3.
}
К>Облом инстанцирования уже считается ошибкой. К>Что касается предпочтений g('a','a') из g<T>(T,T), g<T>(T,char), g(char,char) — как раз из-за того, что компилятор считает, что g<T>(T,T) и g<T>(T,char) одинаково удалены от искомого, (там и возникает ошибка неоднозначности).
С 3мя функциями ошибки как раз нет.
К>"Более специализировано" было бы g<T>(T,T) или g<T>(T,char) перед g<T,U>(T,U)
А в этом случае выборка делается вообще из 2х функций, а не из трёх.
К>Только не проси меня лазать в стандрат сейчас — вечер, голова пухнет...
Я начал тред из практических соображений, стандарт меня здесь мало волнует.
К>[c] К>template<class T, class U> void f(T,U) { cout <<__PRETTY_FUNCTION__<<endl; } К>template<class T> void f(T,T) { cout <<__PRETTY_FUNCTION__<<endl; } К>template<class T> void f(T,char) { cout <<__PRETTY_FUNCTION__<<endl; } К>//void f(char,char) { cout <<__PRETTY_FUNCTION__<<endl; }
К>int x=0; char c=0; К>f(x,c); // T,char T=int К>f(x,x); // T,T T=int К>f(c,x); // T,U T=char,U=int К>f(c,c); // неоднозначность между T,T и T,char, лечится раскомментированием f(char,char)
Можно привести контр пример, где ничего раскомментировать не надо:
Здесь нормально выбирается более детальная специализация, а почему тогда между f<char>(T,T) и f<char>(T,char) — не может?
К>Естественно, компилятор ведёт два списка — сигнатуры конкретных функций и шаблоны функций. К>Причём, несколько разных шаблонов могут инстанцироваться к одной и той же сигнатуре. Но для этого надо особым образом постараться.
Зачем париться, посмотрите мой пример в начале этого поста, там как раз одна и таже сигнатура (вызов функции возможен для обоих инстанций, поэтому ambiguous call).
К>f<char,char>(x,x); // T,U T=char,U=char К>f<int>(x,c); // T,char T=int К>f<int>(c,x); // T,T T=int К>f<int>(c,c); // T,char T=int — вот здесь я затрудняюсь объяснить, почему так.
Здесь выборка прошла только между шаблонными истанциями, т.к. вы явно сказали что используете только их — f<int>(c,c).
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Vain, Вы писали:
К>>Облом инстанцирования уже считается ошибкой. К>>Что касается предпочтений g('a','a') из g<T>(T,T), g<T>(T,char), g(char,char) — как раз из-за того, что компилятор считает, что g<T>(T,T) и g<T>(T,char) одинаково удалены от искомого, (там и возникает ошибка неоднозначности). V>С 3мя функциями ошибки как раз нет.
Ну, я имел в виду: если бы не было g(char,char), то была бы ошибка.
К>>"Более специализировано" было бы g<T>(T,T) или g<T>(T,char) перед g<T,U>(T,U) V>А в этом случае выборка делается вообще из 2х функций, а не из трёх.
Почему же? g<T,U>(T,U), g<T>(T,T), g<T>(T,char) — все подходят для g('a','a').
Только первая требует подстановки двух параметров, а вторая и третья — одного. Вот они и предпочтительнее.
V>Можно привести контр пример, где ничего раскомментировать не надо: V>
V>Здесь нормально выбирается более детальная специализация, а почему тогда между f<char>(T,T) и f<char>(T,char) — не может?
g<T>(T,...) и g<T>(X<T>,...) — вторая более специализирована. Тип X<int> сопоставляется с T[T=X<int>] и X<T>[T=int]. В этом и состоит специализация.
А в случае g<T>(T,T) и g<T>(T,char) — тип char сопоставляется с T и там, и там.
Кстати, интересно посмотреть на шаблонные параметры шаблона.
Т.е. если есть g<T<*>>(T<*>) и g<T>(X<T>) — X<int> сопоставится с T<int>[T<*>=X<*>] и X<T>[T=int] соответственно. Что предпочтительнее? По идее, одинаково. http://codepad.org/8ct3bhM5
К>>Естественно, компилятор ведёт два списка — сигнатуры конкретных функций и шаблоны функций. К>>Причём, несколько разных шаблонов могут инстанцироваться к одной и той же сигнатуре. Но для этого надо особым образом постараться. V>Зачем париться, посмотрите мой пример в начале этого поста, там как раз одна и таже сигнатура (вызов функции возможен для обоих инстанций, поэтому ambiguous call).
Я-то как раз показал, как избавиться от неоднозначности, попросив компилятор выбрать тот или иной шаблон: указав параметры явно.
Ибо, если это не делать, то компилятор вынужден по имени функции и по сигнатуре вызова выбирать перегрузку и сопоставлять параметры.
FYI: сигнатуру вызова можно и вот так заявить
void boo( void(*f)(char,char) );
....
boo(g);
Причём, если есть несколько шаблонов с одинаковыми мета-сигнатурами (template<class T> void g(.....)), там тоже происходит сопоставление — по количеству и виду (class T, template<...>class T, и т.п.) явных параметров, по выводу остальных параметров из аргументов вызова.
Здравствуйте, Кодт, Вы писали:
К>>>"Более специализировано" было бы g<T>(T,T) или g<T>(T,char) перед g<T,U>(T,U) V>>А в этом случае выборка делается вообще из 2х функций, а не из трёх. К>Почему же? g<T,U>(T,U), g<T>(T,T), g<T>(T,char) — все подходят для g('a','a'). К>Только первая требует подстановки двух параметров, а вторая и третья — одного. Вот они и предпочтительнее.
А как определить это без инстанцирования?
Нет, одна из функций выкинута из поиска вообще:
"ComeauTest.c", line 23: error: more than one instance of overloaded function "g"
matches the argument list, the choices that match are:
function template"void g(T, T)"
function template"void g(T, char)"
The argument types that you used are: (char, char)
g('a','1');
^
1 error detected in the compilation of "ComeauTest.c".
V>>Можно привести контр пример, где ничего раскомментировать не надо: V>>
V>>Здесь нормально выбирается более детальная специализация, а почему тогда между f<char>(T,T) и f<char>(T,char) — не может? К>g<T>(T,...) и g<T>(X<T>,...) — вторая более специализирована. Тип X<int> сопоставляется с T[T=X<int>] и X<T>[T=int]. В этом и состоит специализация. К>А в случае g<T>(T,T) и g<T>(T,char) — тип char сопоставляется с T и там, и там.
Т.е. по-вашему g<T>(T,char) не специализация?
К>Кстати, интересно посмотреть на шаблонные параметры шаблона. К>Т.е. если есть g<T<*>>(T<*>) и g<T>(X<T>) — X<int> сопоставится с T<int>[T<*>=X<*>] и X<T>[T=int] соответственно. Что предпочтительнее? По идее, одинаково. http://codepad.org/8ct3bhM5
Это только подтверждает что выборка в двух списках функций идёт по-разному. Никакого интанцирования и простого сравнения как в случае с обычными перегруженными функциями нет.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Vain, Вы писали:
К>>Только первая требует подстановки двух параметров, а вторая и третья — одного. Вот они и предпочтительнее. V>А как определить это без инстанцирования?
Фиг знает. Разжиться дебажной сборкой компилятора. Напихать туда трейсов.
V>Нет, одна из функций выкинута из поиска вообще: V>
V>"ComeauTest.c", line 23: error: more than one instance of overloaded function "g"
V> matches the argument list, the choices that match are:
V> function template"void g(T, T)"
V> function template"void g(T, char)"
V> The argument types that you used are: (char, char)
V> g('a','1');
V> ^
V>1 error detected in the compilation of "ComeauTest.c".
V>
Она (g<T,U>(T,U)) не выкинута из поиска. Она просто отодвинута на второе место, а за первое место борются два претендента.
К>>А в случае g<T>(T,T) и g<T>(T,char) — тип char сопоставляется с T и там, и там. V>Т.е. по-вашему g<T>(T,char) не специализация?
Неа. Это ещё одна перегрузка.
К>>Кстати, интересно посмотреть на шаблонные параметры шаблона. К>>Т.е. если есть g<T<*>>(T<*>) и g<T>(X<T>) — X<int> сопоставится с T<int>[T<*>=X<*>] и X<T>[T=int] соответственно. Что предпочтительнее? По идее, одинаково. http://codepad.org/8ct3bhM5 V>Это только подтверждает что выборка в двух списках функций идёт по-разному. Никакого интанцирования и простого сравнения как в случае с обычными перегруженными функциями нет.
Пойми! На стадии поиска сигнатуры компилятор ничего не инстанцирует.
Он смотрит на объявления и ищет наиболее подходящее.
Правила оценки "наибольшей подходящести", с учётом шаблонов и разных преобразований типов, довольно хитрые.
Здравствуйте, Кодт, Вы писали:
К>>>Только первая требует подстановки двух параметров, а вторая и третья — одного. Вот они и предпочтительнее. V>>А как определить это без инстанцирования? К>Фиг знает. Разжиться дебажной сборкой компилятора. Напихать туда трейсов. V>>Нет, одна из функций выкинута из поиска вообще: V>>
V>>"ComeauTest.c", line 23: error: more than one instance of overloaded function "g"
V>> matches the argument list, the choices that match are:
V>> function template"void g(T, T)"
V>> function template"void g(T, char)"
V>> The argument types that you used are: (char, char)
V>> g('a','1');
V>> ^
V>>1 error detected in the compilation of "ComeauTest.c".
V>>
К>Она (g<T,U>(T,U)) не выкинута из поиска. Она просто отодвинута на второе место, а за первое место борются два претендента.
Какие ваши доводы?
К>>>А в случае g<T>(T,T) и g<T>(T,char) — тип char сопоставляется с T и там, и там. V>>Т.е. по-вашему g<T>(T,char) не специализация? К>Неа. Это ещё одна перегрузка.
Вы так и не объяснили чем оно отличается от той же g<char>(X<T>,char)
К>>>Кстати, интересно посмотреть на шаблонные параметры шаблона. К>>>Т.е. если есть g<T<*>>(T<*>) и g<T>(X<T>) — X<int> сопоставится с T<int>[T<*>=X<*>] и X<T>[T=int] соответственно. Что предпочтительнее? По идее, одинаково. http://codepad.org/8ct3bhM5 V>>Это только подтверждает что выборка в двух списках функций идёт по-разному. Никакого интанцирования и простого сравнения как в случае с обычными перегруженными функциями нет. К>Пойми! На стадии поиска сигнатуры компилятор ничего не инстанцирует. К>Он смотрит на объявления и ищет наиболее подходящее. К>Правила оценки "наибольшей подходящести", с учётом шаблонов и разных преобразований типов, довольно хитрые.
Это расходится с тем что написал здесь
Здравствуйте, Vain, Вы писали:
V>>>Нет, одна из функций выкинута из поиска вообще: К>>Она (g<T,U>(T,U)) не выкинута из поиска. Она просто отодвинута на второе место, а за первое место борются два претендента. V>Какие ваши доводы?
Очень простые: достаточно закомментировать (или засфинаить) этих кандидатов, и она немедленно выберется как наилучшая.
К>>>>А в случае g<T>(T,T) и g<T>(T,char) — тип char сопоставляется с T и там, и там. V>>>Т.е. по-вашему g<T>(T,char) не специализация? К>>Неа. Это ещё одна перегрузка. V>Вы так и не объяснили чем оно отличается от той же g<char>(X<T>,char)
Итак. У нас есть три перегрузки имени g: g<T>(T,T), g<T>(T,char), g(char,char). Два шаблона функции и обычная функция.
Заметь! Это два разных шаблона!
То же касается ситуации, когда есть g<T>(T) и g<T>(X<T>). Это опять два шаблона, а не основной шаблон и его частичная специализация.
ДОВОД: попробуй определить тип g<int>. Компилятор выругается, потому что не поймёт, в какой из двух шаблонов подставлять.
Частичной специализации шаблонов функций нет, в отличие от шаблонов классов.
Зато есть одноимённые шаблоны, и пусть у компилятора (и у программиста) башка болит, как их отличать друг от друга.
V>Это расходится с тем что написал здесь
ЮЖ: V>Специализации шаблонов функций участвуют в процессе разрешениия перегрузки наравне с non-template функциями.
Не расходится.
V>Т.е. вы подтвердили что оно участвует не наравне.
Это всё равно, что сказать g(long) участвует не наравне с g(char) в процессе разрешения g('a').
Ясное дело, что к финишу "придёт первым" кто-то один либо толпа (и забег будет считаться неудачным).
Но стартуют все с одной ленточки. В этом смысле наравне.
V>Никакого интанцирования и простого сравнения как в случае с обычными перегруженными функциями нет.
Я конечно понимаю что "стандарт меня здесь мало волнует", но все же:
14.7.1/8
If a function template or a member function template specialization is used in a way that involves overload resolution, a declaration of the specialization is implicitly instantiated
+
14.8.3/6
Only the signature of a function template specialization is needed to enter the specialization in a set of candidate functions. Therefore only the function template declaration is needed to resolve a call for which a template specialization is a candidate.
+
13.3.1/7
In each case where a candidate is a function template, candidate function template specializations are generated using template argument deduction (14.8.3, 14.8.2). Those candidates are then handled as candidate functions in the usual way. A given name can refer to one or more function templates and also to a set of overloaded non-template functions. In such a case, the candidate functions generated from each function template are combined with the set of non-template candidate functions.
По поводу сравнения:
13.3.3/1
...
a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then
— for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,
— F1 is a non-template function and F2 is a function template specialization, ...
Это 'explicit specialization'. В противовес 14.8/1 — "A function instantiated from a function template is called a function template specialization".
V>>Т.е. вы подтвердили что оно участвует не наравне.
К>Это всё равно, что сказать g(long) участвует не наравне с g(char) в процессе разрешения g('a'). К>Ясное дело, что к финишу "придёт первым" кто-то один либо толпа (и забег будет считаться неудачным). К>Но стартуют все с одной ленточки. В этом смысле наравне.
Здравствуйте, Юрий Жмеренецкий, Вы писали:
V>>Никакого интанцирования и простого сравнения как в случае с обычными перегруженными функциями нет. ЮЖ>Я конечно понимаю что "стандарт меня здесь мало волнует", но все же: ЮЖ>
14.7.1/8
ЮЖ>If a function template or a member function template specialization is used in a way that involves overload resolution, a declaration of the specialization is implicitly instantiated
ЮЖ>+ ЮЖ>
14.8.3/6
ЮЖ>Only the signature of a function template specialization is needed to enter the specialization in a set of candidate functions. Therefore only the function template declaration is needed to resolve a call for which a template specialization is a candidate.
13.3.1/7
ЮЖ>In each case where a candidate is a function template, candidate function template specializations are generated using template argument deduction (14.8.3, 14.8.2). Those candidates are then handled as candidate functions in the usual way. A given name can refer to one or more function templates and also to a set of overloaded non-template functions. In such a case, the candidate functions generated from each function template are combined with the set of non-template candidate functions.
Ну т.е. dedution в первом этапе, а выборка из combined списка на втором?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
13.3.1/7
ЮЖ>>In each case where a candidate is a function template, candidate function template specializations are generated using template argument deduction (14.8.3, 14.8.2). Those candidates are then handled as candidate functions in the usual way. A given name can refer to one or more function templates and also to a set of overloaded non-template functions. In such a case, the candidate functions generated from each function template are combined with the set of non-template candidate functions.
V>Ну т.е. dedution в первом этапе
Да. Только здесь template argument deduction не учитывает наличие любых других функций.
V>а выборка из combined списка на втором?
Да. В некоторых случаях при выборе best viable функции также может происходить template argument deduction (14.5.5.2/4), но в специфической форме. Это необходимо для выяснения более специализированной function template specialization.
Здравствуйте, Masterkent, Вы писали:
ЮЖ>>1) Формируется набор candidate functions M>Формирование набора кандидатов происходит в 2 этапа и не является частью разрешения перегрузки.
Согласен, но здесь есть некоторые несоответствия:
14.8.3/2
...
The function template specializations are treated like any other functions in the remainder of overload resolution, except as explicitly noted in 13.3.3.
Сноска к 13.3.1/7:
...Therefore the function template specializations can be treated as normal (non-template) functions for the remainder of overload resolution.
13.3.1/7
ЮЖ>>>In each case where a candidate is a function template, candidate function template specializations are generated using template argument deduction (14.8.3, 14.8.2). Those candidates are then handled as candidate functions in the usual way. A given name can refer to one or more function templates and also to a set of overloaded non-template functions. In such a case, the candidate functions generated from each function template are combined with the set of non-template candidate functions.
V>>Ну т.е. dedution в первом этапе ЮЖ>Да. Только здесь template argument deduction не учитывает наличие любых других функций. V>>а выборка из combined списка на втором? ЮЖ>Да. В некоторых случаях при выборе best viable функции также может происходить template argument deduction (14.5.5.2/4), но в специфической форме. Это необходимо для выяснения более специализированной function template specialization.
Тогда я не понимаю с чем вы здесь
не согласны. V>>Обычно выборка между списком перегруженных функций и шаблоном происходит до выборки между самими перегруженными функциями ЮЖ>Такого (отдельного) этапа как 'выборка между самими перегруженными функциями' не существует, т.к. среди кандидатов могут оказаться и специализации.
Ну значит с двумя этапами вы всё-таки согласны
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]