Re[2]: Template && reference
От: AnatolyDu  
Дата: 13.02.22 20:52
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>Здравствуйте, AnatolyDu, Вы писали:


AD>>Что-то я не "догоняю"...

AD>>Что не так с reference ?

Большое спасибо за подробный ответ !!!
Но, пару вопросов всё-таки есть

АТ>Все не так. В С++ шаблонах, если некий дедуцируемый шаблонный параметр `T` можно успешно дедуцировать из нескольких аргументов функции, то все результаты таких дедукций должны точно совпадать. Малейшее несовпадение является ошибкой. В вашем случае в варианте `fCaller( &fReference, strParam )` шаблонный параметр `TArguments` можно дедуцировать и из первого параметра функции, и из второго. Дедукция из первого дает `const std::string &`, а из второго — просто `std::string`. Это — разные типы. Получаем неоднозначную дедукцию.


А почему из второго аргумента выводится std::string, а не const std::string& ?
Ведь он имеет явный тип const std::string& — const std::string &strParam ?

AD>>Хочу написать функцию, получающую другую функцию( указатель на неё ) и её аргументы (разного количества и типов) :


АТ>Написание таких шаблонов часто приводит к тому, что вы будете сталкиваться с проблемой несоответствия типа переданных аргументов с типами параметров функции. В обыкновенном вызове функции такого соответствия и не требуется — вы можете спокойно передавать аргумент типа `char` в функцию, ожидающую параметра типа `int` и т.п. А когда речь заходит о дедукции шаблонных аргументов, такие вольности уже не являются допустимыми.


Я как раз и хочу, что бы компилятор указал мне на это несоответстие — мне нужно, что всё полностью совпадало...

АТ>Первый вопрос, возникающий в таких случаях: а зачем вам вообще понадобилось объявлять параметр `a_FuncToCall` как именно указатель на функцию? Почему бы вам не завязаться на свободный duck typing и не сделать просто


АТ>
АТ>template<typename F, typename... TArguments>
АТ>void fCaller(F a_FuncToCall, TArguments ... arguments)
АТ>{
АТ>  a_FuncToCall( arguments... );
АТ>}
АТ>


АТ>и забыть о всех проблемах? Такой вариант будет компилироваться для обоих ваших вызовов. (Я не хочу пока касаться вопроса о правильном форвардинге аргументов.)


Такой вариант меня вполне устраивает — с "замаскированным" указателем на функцию через аргумент шаблона... ну, если закрыть глаза на то, что char вместо int отлично скомпилируется...



АТ>Второй вопрос, возникающий в таких случаях: если уж вы зачем-то хотите, чтобы ваш параметр был именно указателем на функцию — ваше право. В такой ситуации для того, чтобы получше воспроизвести "натуральное" поведение функций можно попробовать намеренно поместить типы параметров в non-deduced context, то есть умышленно подавить дедукцию шаблонных параметров из `arguments`


АТ>
АТ>// C++20
АТ>template<typename... TArguments>
АТ>void fCaller( FunctionToCall<TArguments...> a_FuncToCall, std::type_identity_t<TArguments>... arguments)
АТ>{
АТ>  a_FuncToCall( arguments... );
АТ>}
АТ>


У меня пока что не C++20

АТ>В такой ситуации типы `TArguments` будут дедуцироваться исключительно из типа функции. Такой вариант тоже будет компилироваться для обоих ваших вызовов


АТ>Но, еще раз, мне кажется что лучше было бы положиться на обычный duck typing для типа функтора и сделать обычный форвардинг всех параметров. А если вам хочется как-то ограничить разнообразие допустимых типов функторов, то сделать это можно уже поверх: через концепты или `std::enable_if`.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.