Выделяется два или более любых типа, 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.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, 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
...
Здравствуйте, Юрий Жмеренецкий, Вы писали:
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.]
[Даю очевидные ответы на риторические вопросы]