Сообщение Re[3]: Template && reference от 13.02.2022 21:30
Изменено 13.02.2022 21:38 Андрей Тарасевич
Re[3]: Template && reference
Здравствуйте, AnatolyDu, Вы писали:
АТ>>Все не так. В С++ шаблонах, если некий дедуцируемый шаблонный параметр `T` можно успешно дедуцировать из нескольких аргументов функции, то все результаты таких дедукций должны точно совпадать. Малейшее несовпадение является ошибкой. В вашем случае в варианте `fCaller( &fReference, strParam )` шаблонный параметр `TArguments` можно дедуцировать и из первого параметра функции, и из второго. Дедукция из первого дает `const std::string &`, а из второго — просто `std::string`. Это — разные типы. Получаем неоднозначную дедукцию.
AD>А почему из второго аргумента выводится std::string, а не const std::string& ?
AD>Ведь он имеет явный тип const std::string& — const std::string &strParam ?
Здесь работает два момента:
1. Аргумент `strParam`, который вы передаете в вызов — это выражение. Правила обработки выражений в С++ говорят, что если выражение имеет ссылочный тип, то этот ссылочный тип немедленно теряется и все дальнейшее рассмотрение делается для нессылочного типа: http://eel.is/c++draft/expr.type#1
То есть согласно этому пункту ваш тип `const std::string &` сразу превращается в тип `const std::string`
2. Далее, в описании процесса дедукции шаблонных аргументов говорится, что для нессылочных параметров функции верхние cv-квалификаторы ее аргументов игнорируются: http://eel.is/c++draft/temp.deduct.call#2.3
Согласно этому пункту для целей дедукции ваш тип `const std::string` превращается в тип `std::string`.
AD>>>Хочу написать функцию, получающую другую функцию( указатель на неё ) и её аргументы (разного количества и типов) :
АТ>>Второй вопрос, возникающий в таких случаях: если уж вы зачем-то хотите, чтобы ваш параметр был именно указателем на функцию — ваше право. В такой ситуации для того, чтобы получше воспроизвести "натуральное" поведение функций можно попробовать намеренно поместить типы параметров в non-deduced context, то есть умышленно подавить дедукцию шаблонных параметров из `arguments`
АТ>>
AD>У меня пока что не C++20
C++20 тут чисто номинально — для `std::type_identity_t`. Никто вам даже в С++98 не мешает написать самостоятельно
и далее использовать `typename non_deduced<...>::type` вместо `std::type_identity_t<...>`.
АТ>>Все не так. В С++ шаблонах, если некий дедуцируемый шаблонный параметр `T` можно успешно дедуцировать из нескольких аргументов функции, то все результаты таких дедукций должны точно совпадать. Малейшее несовпадение является ошибкой. В вашем случае в варианте `fCaller( &fReference, strParam )` шаблонный параметр `TArguments` можно дедуцировать и из первого параметра функции, и из второго. Дедукция из первого дает `const std::string &`, а из второго — просто `std::string`. Это — разные типы. Получаем неоднозначную дедукцию.
AD>А почему из второго аргумента выводится std::string, а не const std::string& ?
AD>Ведь он имеет явный тип const std::string& — const std::string &strParam ?
Здесь работает два момента:
1. Аргумент `strParam`, который вы передаете в вызов — это выражение. Правила обработки выражений в С++ говорят, что если выражение имеет ссылочный тип, то этот ссылочный тип немедленно теряется и все дальнейшее рассмотрение делается для нессылочного типа: http://eel.is/c++draft/expr.type#1
То есть согласно этому пункту ваш тип `const std::string &` сразу превращается в тип `const std::string`
2. Далее, в описании процесса дедукции шаблонных аргументов говорится, что для нессылочных параметров функции верхние cv-квалификаторы ее аргументов игнорируются: http://eel.is/c++draft/temp.deduct.call#2.3
Согласно этому пункту для целей дедукции ваш тип `const std::string` превращается в тип `std::string`.
AD>>>Хочу написать функцию, получающую другую функцию( указатель на неё ) и её аргументы (разного количества и типов) :
АТ>>Второй вопрос, возникающий в таких случаях: если уж вы зачем-то хотите, чтобы ваш параметр был именно указателем на функцию — ваше право. В такой ситуации для того, чтобы получше воспроизвести "натуральное" поведение функций можно попробовать намеренно поместить типы параметров в non-deduced context, то есть умышленно подавить дедукцию шаблонных параметров из `arguments`
АТ>>
АТ>>// C++20
АТ>>template<typename... TArguments>
АТ>>void fCaller( FunctionToCall<TArguments...> a_FuncToCall, std::type_identity_t<TArguments>... arguments)
АТ>>{
АТ>> a_FuncToCall( arguments... );
АТ>>}
АТ>>
AD>У меня пока что не C++20
C++20 тут чисто номинально — для `std::type_identity_t`. Никто вам даже в С++98 не мешает написать самостоятельно
template <typename T>
struct non_deduced
{
typedef T type;
};
и далее использовать `typename non_deduced<...>::type` вместо `std::type_identity_t<...>`.
Re[3]: Template && reference
Здравствуйте, AnatolyDu, Вы писали:
АТ>>Все не так. В С++ шаблонах, если некий дедуцируемый шаблонный параметр `T` можно успешно дедуцировать из нескольких аргументов функции, то все результаты таких дедукций должны точно совпадать. Малейшее несовпадение является ошибкой. В вашем случае в варианте `fCaller( &fReference, strParam )` шаблонный параметр `TArguments` можно дедуцировать и из первого параметра функции, и из второго. Дедукция из первого дает `const std::string &`, а из второго — просто `std::string`. Это — разные типы. Получаем неоднозначную дедукцию.
AD>А почему из второго аргумента выводится std::string, а не const std::string& ?
AD>Ведь он имеет явный тип const std::string& — const std::string &strParam ?
Здесь работает два момента:
1. Аргумент `strParam`, который вы передаете в вызов — это выражение. Правила обработки выражений в С++ говорят, что если выражение имеет ссылочный тип, то этот ссылочный тип немедленно теряется и все дальнейшее рассмотрение делается для нессылочного типа: http://eel.is/c++draft/expr.type#1
То есть согласно этому пункту ваш тип `const std::string &` сразу превращается в тип `const std::string`
2. Далее, в описании процесса дедукции шаблонных аргументов говорится, что для нессылочных параметров функции верхние cv-квалификаторы ее аргументов игнорируются: http://eel.is/c++draft/temp.deduct.call#2.3
Согласно этому пункту для целей дедукции ваш тип `const std::string` превращается в тип `std::string`.
По этой причине нет никакой разницы, указывать ли в качестве аргумента `strString` или `strParam` — дедукция в обоих случаях дедуцирует один и тот же тип. Как часто говорят, именованную ссылку в языке С++ можно рассматривать как альтернативное имя для того же самого объекта. Язык С++ специально предпринимает усилия для того, чтобы скрыть различия между именованным объектом и именованной ссылкой на этот же объект. Оба способа доступа ведут себя внешне одинаково.
AD>>>Хочу написать функцию, получающую другую функцию( указатель на неё ) и её аргументы (разного количества и типов) :
АТ>>Второй вопрос, возникающий в таких случаях: если уж вы зачем-то хотите, чтобы ваш параметр был именно указателем на функцию — ваше право. В такой ситуации для того, чтобы получше воспроизвести "натуральное" поведение функций можно попробовать намеренно поместить типы параметров в non-deduced context, то есть умышленно подавить дедукцию шаблонных параметров из `arguments`
АТ>>
AD>У меня пока что не C++20
C++20 тут чисто номинально — для `std::type_identity_t`. Никто вам даже в С++98 не мешает написать самостоятельно
и далее использовать `typename non_deduced<...>::type` вместо `std::type_identity_t<...>`.
АТ>>Все не так. В С++ шаблонах, если некий дедуцируемый шаблонный параметр `T` можно успешно дедуцировать из нескольких аргументов функции, то все результаты таких дедукций должны точно совпадать. Малейшее несовпадение является ошибкой. В вашем случае в варианте `fCaller( &fReference, strParam )` шаблонный параметр `TArguments` можно дедуцировать и из первого параметра функции, и из второго. Дедукция из первого дает `const std::string &`, а из второго — просто `std::string`. Это — разные типы. Получаем неоднозначную дедукцию.
AD>А почему из второго аргумента выводится std::string, а не const std::string& ?
AD>Ведь он имеет явный тип const std::string& — const std::string &strParam ?
Здесь работает два момента:
1. Аргумент `strParam`, который вы передаете в вызов — это выражение. Правила обработки выражений в С++ говорят, что если выражение имеет ссылочный тип, то этот ссылочный тип немедленно теряется и все дальнейшее рассмотрение делается для нессылочного типа: http://eel.is/c++draft/expr.type#1
То есть согласно этому пункту ваш тип `const std::string &` сразу превращается в тип `const std::string`
2. Далее, в описании процесса дедукции шаблонных аргументов говорится, что для нессылочных параметров функции верхние cv-квалификаторы ее аргументов игнорируются: http://eel.is/c++draft/temp.deduct.call#2.3
Согласно этому пункту для целей дедукции ваш тип `const std::string` превращается в тип `std::string`.
По этой причине нет никакой разницы, указывать ли в качестве аргумента `strString` или `strParam` — дедукция в обоих случаях дедуцирует один и тот же тип. Как часто говорят, именованную ссылку в языке С++ можно рассматривать как альтернативное имя для того же самого объекта. Язык С++ специально предпринимает усилия для того, чтобы скрыть различия между именованным объектом и именованной ссылкой на этот же объект. Оба способа доступа ведут себя внешне одинаково.
AD>>>Хочу написать функцию, получающую другую функцию( указатель на неё ) и её аргументы (разного количества и типов) :
АТ>>Второй вопрос, возникающий в таких случаях: если уж вы зачем-то хотите, чтобы ваш параметр был именно указателем на функцию — ваше право. В такой ситуации для того, чтобы получше воспроизвести "натуральное" поведение функций можно попробовать намеренно поместить типы параметров в non-deduced context, то есть умышленно подавить дедукцию шаблонных параметров из `arguments`
АТ>>
АТ>>// C++20
АТ>>template<typename... TArguments>
АТ>>void fCaller( FunctionToCall<TArguments...> a_FuncToCall, std::type_identity_t<TArguments>... arguments)
АТ>>{
АТ>> a_FuncToCall( arguments... );
АТ>>}
АТ>>
AD>У меня пока что не C++20
C++20 тут чисто номинально — для `std::type_identity_t`. Никто вам даже в С++98 не мешает написать самостоятельно
template <typename T>
struct non_deduced
{
typedef T type;
};
и далее использовать `typename non_deduced<...>::type` вместо `std::type_identity_t<...>`.