Здравствуйте, Vain, Вы писали:
V>>>Обычно выборка между списком перегруженных функций и шаблоном происходит до выборки между самими перегруженными функциями, т.е. в два этапа, что не эквивалентно выборки функции просто из списка перегруженных функций.
ЮЖ>>Нет никаких двух этапов:
... ЮЖ>>Разница проявляется только при выборе Best Viable Function (13.3.3/1) V>Не видел чтобы шаблон выбирался на уровне перегруженных функций. Пример бы не помешал такого поведения.
Специализации шаблонов функций участвуют в процессе разрешениия перегрузки наравне с non-template функциями. Именно поэтому следующий пример является ill-formed:
т.к. среди функций 'g<char>(char, long)' и 'g(long, char)' невозможно выбрать наиболее подходящую.
Факт того, что viable function представляет из себя специализацию, становится значимым только при выполнении следующих условий:
... 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
...
Выделяется два или более любых типа, Type1...TypeN, для которых реализуется такая шаблонная функция:
template<class T1, class T2> void f(T1 &t1, T2 &t2)
Если хотябы один её параметр имеет тип не из набора, то механизм SFINAE может подставить другую перегруженную функцию f, наличие которой не должно вносить неразбериху. Короче, должна работать перегрузка:
Здравствуйте, wobist, Вы писали:
W>Выделяется два или более любых типа, Type1...TypeN, для которых реализуется такая шаблонная функция: W>... W>так, чтобы полноценно работал механизм выбора перегруженных функций через SFINAE, как реализовать набор типов?
Тогда нужно сделать уже перегруженные функции частью шаблона, а внутри дергать имплементацию.
Не совсем понял, что ты хочешь получить. Но вот мое виденье (набросал на скорую руку, если кто скорректирует в лучшую сторону, будет интересно посмотреть):
Это приведёт к тому, что f_impl_tmpl будет воплощаться для всех типов, а не только для "хороших". Хотя и не будет вызываться.
Как следствие, можно получить ошибку компиляции — если тип T1 или T2 не подходит для f_impl_tmpl.
Например, f_impl_tmpl требует, что её параметры — это указатели. Разыменовывает их внутри. Не-указатель, понятное дело, не подойдёт.
V>>Пойдёт? W>Пойдёт, если такого на шаблонах сделать нельзя. W>Разве выделенная строка не реализуется на шаблонах (вместе с ||)?
Это и предложено дорешать
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
К>Это приведёт к тому, что f_impl_tmpl будет воплощаться для всех типов, а не только для "хороших". Хотя и не будет вызываться. К>Как следствие, можно получить ошибку компиляции — если тип T1 или T2 не подходит для f_impl_tmpl. К>Например, f_impl_tmpl требует, что её параметры — это указатели. Разыменовывает их внутри. Не-указатель, понятное дело, не подойдёт.
Это уже детали, решаемые, можно сделать "пустую" реализацию по-умолчанию, которая не будет вызываться, но и не будет приводить к ошибкам компиляции.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Vain, Вы писали:
К>>Это приведёт к тому, что f_impl_tmpl будет воплощаться для всех типов, а не только для "хороших". Хотя и не будет вызываться. К>>Как следствие, можно получить ошибку компиляции — если тип T1 или T2 не подходит для f_impl_tmpl. К>>Например, f_impl_tmpl требует, что её параметры — это указатели. Разыменовывает их внутри. Не-указатель, понятное дело, не подойдёт. V>Это уже детали, решаемые, можно сделать "пустую" реализацию по-умолчанию, которая не будет вызываться, но и не будет приводить к ошибкам компиляции.
Но если мы делаем пустую реализацию по умолчанию — и непустую по неумолчанию, то почему бы сразу не сделать их, без функции-диспетчера?
Только вместо пустой реализации подставить "другую перегруженную".
На самом деле, диспетчер может пригодиться, если у нас громоздкие условия для выбора из многих перегрузок.
Поскольку все перегрузки равны перед компилятором, то сделать цепочку if(a)-elseif(b)-elseif(c)-...-else довольно мучительно, она превращается в россыпь
if(a)
if(!a && b)
if(!a && !b && c)
...
if(!a && !b && !c && ...)
Здравствуйте, Vain, Вы писали:
W>>Разве выделенная строка не реализуется на шаблонах (вместе с ||)? V>Это и предложено дорешать
"Мыши, это ваши проблемы — КАК стать ёжиками, а я — стратег".
Здравствуйте, Кодт, Вы писали:
К>>>Это приведёт к тому, что f_impl_tmpl будет воплощаться для всех типов, а не только для "хороших". Хотя и не будет вызываться. К>>>Как следствие, можно получить ошибку компиляции — если тип T1 или T2 не подходит для f_impl_tmpl. К>>>Например, f_impl_tmpl требует, что её параметры — это указатели. Разыменовывает их внутри. Не-указатель, понятное дело, не подойдёт. V>>Это уже детали, решаемые, можно сделать "пустую" реализацию по-умолчанию, которая не будет вызываться, но и не будет приводить к ошибкам компиляции. К>Но если мы делаем пустую реализацию по умолчанию — и непустую по неумолчанию, то почему бы сразу не сделать их, без функции-диспетчера? К>Только вместо пустой реализации подставить "другую перегруженную".
Обычно выборка между списком перегруженных функций и шаблоном происходит до выборки между самими перегруженными функциями, т.е. в два этапа, что не эквивалентно выборки функции просто из списка перегруженных функций.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Кодт, Вы писали:
W>>>Разве выделенная строка не реализуется на шаблонах (вместе с ||)? V>>Это и предложено дорешать К>"Мыши, это ваши проблемы — КАК стать ёжиками, а я — стратег".
Это не имеет отношение к исходному вопросу, это уже другая тема про программирование в compile time'е. Тем более было упомянуто ключевое слово — SFINAE.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Vain, Вы писали:
К>>Только вместо пустой реализации подставить "другую перегруженную". V>Обычно выборка между списком перегруженных функций и шаблоном происходит до выборки между самими перегруженными функциями, т.е. в два этапа, что не эквивалентно выборки функции просто из списка перегруженных функций.
Нет никаких двух этапов:
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 (^113) 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.
----------------
^113 The process of argument deduction fully determines the parameter types of the function template specializations, i.e., the parameters of function template specializations contain no template parameter types. Therefore the function template specializations can be treated as normal (non-template) functions for the remainder of overload resolution.
Разница проявляется только при выборе Best Viable Function (13.3.3/1)
Здравствуйте, Юрий Жмеренецкий, Вы писали:
К>>>Только вместо пустой реализации подставить "другую перегруженную". V>>Обычно выборка между списком перегруженных функций и шаблоном происходит до выборки между самими перегруженными функциями, т.е. в два этапа, что не эквивалентно выборки функции просто из списка перегруженных функций. ЮЖ>
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 (^113) 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.
ЮЖ>----------------
ЮЖ>^113 The process of argument deduction fully determines the parameter types of the function template specializations, i.e., the parameters of function template specializations contain no template parameter types. Therefore the function template specializations can be treated as normal (non-template) functions for the remainder of overload resolution.
ЮЖ>Разница проявляется только при выборе Best Viable Function (13.3.3/1)
Не видел чтобы шаблон выбирался на уровне перегруженных функций. Пример бы не помешал такого поведения.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Юрий Жмеренецкий, Вы писали:
V>>>>Обычно выборка между списком перегруженных функций и шаблоном происходит до выборки между самими перегруженными функциями, т.е. в два этапа, что не эквивалентно выборки функции просто из списка перегруженных функций. ЮЖ>>>Нет никаких двух этапов: ЮЖ>... ЮЖ>>>Разница проявляется только при выборе Best Viable Function (13.3.3/1) V>>Не видел чтобы шаблон выбирался на уровне перегруженных функций. Пример бы не помешал такого поведения. ЮЖ>Специализации шаблонов функций участвуют в процессе разрешениия перегрузки наравне с non-template функциями. Именно поэтому следующий пример является ill-formed: ЮЖ>
ЮЖ>т.к. среди функций 'g<char>(char, long)' и 'g(long, char)' невозможно выбрать наиболее подходящую. ЮЖ>Факт того, что viable function представляет из себя специализацию, становится значимым только при выполнении следующих условий:
А как вы объясните это?
К тому же SFINAE бы просто не работало при одном проходе-этапе компилятора, т.к. оно как-бе основано на отсечении деклараций функций из списка поиска, что и должен делать первый этап.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравым смыслом, как ещё. g(T,char)[T=char] подходит лучше, чем g(char,long), потому что не требует приведения типа.
А вот если бы было ещё g(char,char), то g(T,char)[T=char] будет хуже, потому что требует подстановки.
V>К тому же SFINAE бы просто не работало при одном проходе-этапе компилятора, т.к. оно как-бе основано на отсечении деклараций функций из списка поиска, что и должен делать первый этап.
Как раз оно за один проход и работает.
Компилятор перебирает все видимые сигнатуры, подставляет типы аргументов и тут же даёт оценку — расстояние от идеала.
Если из-за SFINAE подстановка не удалась (substitution failure), — игнорирует данную сигнатуру (is not an error).
Затем ранжирует всё полученное и выбирает наилучшее.
Если наилучших несколько — ругается про неоднозначность.
Что здесь нужно объяснять?
V>К тому же SFINAE бы просто не работало при одном проходе-этапе компилятора, т.к. оно как-бе основано на отсечении деклараций функций из списка поиска, что и должен делать первый этап.
Процесс разрешения перегрузки выглядит так (очень упрощенно):
1) Формируется набор candidate functions
2) Из него выбираются viable functions
3) Из набора viable функций выбирается best viable функция
4) Если такую функцию удалось выбрать, то она является результатом
Результатом работы SFINAE (а точнее того, о чем идет речь в 14.8.3/1) является набор специализаций (не шаблонов), который добавляется в набор candidate functions. В дальнейшем эти специализации неотличимы от non-template функций, за исключением того, что последние имеет преимущество в некоторых случаях. В частности здесь:
template<class T>
int g(T);
void g(int);
int main()
{
sizeof(g(1)); // error
}
К>Здравым смыслом, как ещё. g(T,char)[T=char] подходит лучше, чем g(char,long), потому что не требует приведения типа. К>А вот если бы было ещё g(char,char), то g(T,char)[T=char] будет хуже, потому что требует подстановки.
Т.е. по логике компилятор должен выбирать более детальную инстанцию функции уже после инстанцирования?
Если так, то получается как сказал ЮЖ две "инстанции":
То ambigous пропадёт, т.е. получается перегруженные функции в одном списке, а инстанции шаблонов в другом и получается этот второй список просто проигнорировался. Т.е. более специализированная функция из шаблонного списка функций не может выбраться, но при этом из нешаблонного спокойно выбирается.
V>>К тому же SFINAE бы просто не работало при одном проходе-этапе компилятора, т.к. оно как-бе основано на отсечении деклараций функций из списка поиска, что и должен делать первый этап. К>Как раз оно за один проход и работает.
Мне кажется что нет, иначе ambiguous был бы.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, 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.]
[Даю очевидные ответы на риторические вопросы]