Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.207.133.13] |
|
Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Здравствуйте!
Вроде бы банальность, но я запутался или чего-то не понимаю. Требуется шаблон функции get_valueof, которая разыменовывает указатель, а если же он нулевой, то возвращает значение по умолчанию. Алгоритм простейший. template< typename ValueType > auto get_valueof( ValueType*ptr, ValueType& value ) -> ValueType& { if( nullptr == ptr ) return value; else return *ptr; } Ссылочность возвращаемого значения и значения по умолчанию желательна, чтобы не копировать толстые объекты. И вот тут начинаются трудности. А ещё с модификатором константности. Компилятор путается и не знает, какие подставить шаблонные параметры. А если перегружаю функцию, то он не может выбрать наиболее подходящий вариант. Сделал простенькие тесты, для четырёх вариантов, которые у меня не проходят. // разыменование константного указателя и константного значения void test1() { const int def1 = 0; const int val1 = 1; const int*const ptr1 = &val1; const int*const zero1 = nullptr; assert( 1 == get_valueof( ptr1, def1 )); assert( 0 == get_valueof( zero1, def1 )); assert( ( std::is_same_v< const int&, decltype( get_valueof( ptr1, def1 ) ) > ) ); } // разыменование константного указателя и неконстантного значения void test2() { int def1 = 0; const int val1 = 1; const int*const ptr1 = &val1; const int*const zero1 = nullptr; assert( 1 == get_valueof( ptr1, def1 )); assert( 0 == get_valueof( zero1, def1 )); assert( ( std::is_same_v< const int&, decltype( get_valueof( ptr1, def1 ) ) > ) ); } // разыменование указателя и константного значения void test3() { const int def1 = 0; int val1 = 1; int* ptr1 = &val1; int* zero1 = nullptr; assert( 1 == get_valueof( ptr1, def1 )); assert( 0 == get_valueof( zero1, def1 )); assert( ( std::is_same_v< const int&, decltype( get_valueof( ptr1, def1 ) ) > ) ); } // разыменование указателя и значения void test4() { int def1 = 0; int val1 = 1; int* ptr1 = &val1; int* zero1 = nullptr; assert( 1 == get_valueof( ptr1, def1 )); assert( 0 == get_valueof( zero1, def1 )); assert( ( std::is_same_v< int&, decltype( get_valueof( ptr1, def1 ) ) > ) ); } // точка входа int main() { test1(); test2(); test3(); test4(); return 0; } Дальше я начал упарываться, сфинае прикручивать с проверкой is_const_v, шаблонные типы разделять и творить прочую ерунду, которая не дала пользы. Дополнительно, было бы очень хорошо, если бы get_valueof, кроме простых указателей, могла бы работать с умными указателями. Там я думал использовать pointer_traits::element_type для типа возвращаемого значения. Наверное, он и для обычного указателя сгодится. Но чего-то у меня не стыкуется. |
Сообщ.
#2
,
|
|
|
Eric-S, я разделяю твою озабоченность в данном вопросе. что ответить, пока не знаю.
Но, прошу рассказать про практическую ценность вопроса, примеры предполагаемого применения. Просто для предварительной "ориентации". |
Сообщ.
#3
,
|
|
|
Eric-S, зачем за компилятор делать то, что он и сам умеет?
template< typename PtrType , typename ValueType> auto get_valueof( PtrType*ptr, ValueType& value ) -> ValueType& |
Сообщ.
#4
,
|
|
|
Цитата Majestio @ прошу рассказать про практическую ценность вопроса, примеры предполагаемого применения. Просто для предварительной "ориентации". В нулевых, делаю рефакторинг старого кода, а там примерно тследующий макрос: #define get_pointerof( ptr, value ) (( nullptr == (ptr))? (value): (*ptr)) Но макросы это зло, которые нужно постаратся заменить шаблонными функциями. Во-первых, синтаксический сахар, для сокращения или упращения кода. void callback_proc( const int*const data ) { std::cout << "data=" << get_valueof( data, 0 ) << std::endl; } Это особо актуально, когда получаются длинные функции, на стыке C++ и разных API в стиле языка C. Забавно, что изначально думается, будто бы подобных ситуаций мало. Ну, их действительно не много, особенно в проектах написанных по феншую. Но всё же иногда возникает нужда применить в самых неожиданных местах. Так что пусть будет, для наглядности. Во-вторых, ради симетрии. У меня используется функция set_valueof. Она, тоже для сахара, слегка упращает жизнь. void callback_proc( const int category, int*const result ) { switch( category ) { case 1: set_valueof( result, 1 ); default: set_valueof( result, 0 ); } } Лениво писать одни и те же условия по несколько раз, раздувая код. Сокращение минимально, но оно всё же есть . В-третьих, собственно get_valueof, простой пример функции, код которой можно выложить на форуме, чтобы продемонстрировать возникшие затруднения. Мне же хочется понять суть проблемы и способ её решения, чтобы использовать для других, более сложных функций. А это всего лишь подопытный котёнок, на котором можно экспериментировать. |
Сообщ.
#5
,
|
|
|
Хотя логичнее всё ж
auto get_valueof( PtrType*ptr, ValueType& value ) -> PtrType& |
Сообщ.
#6
,
|
|
|
Цитата Eric-S @ В нулевых, делаю рефакторинг старого кода, а там примерно тследующий макрос: Ну не знаю. Я тоже всегда за фэн-шуй топлю, но, в твоем случае, я просто бы твой макро оформил функцией, желательно inline. А сэкономленное время направил бы в другой поток. |
Сообщ.
#7
,
|
|
|
Цитата Qraizer @ Пусть сам проверяет возможность вернуть value через тип *ptr Visual studio 2022 std==c++20 выдаёт: Цитата main.cpp main.cpp(17): error C2440: return: невозможно преобразовать "PtrType" в "ValueType &" with [ PtrType=const int ] and [ ValueType=int ] main.cpp(17): note: В результате преобразования теряются квалификаторы main.cpp(43): note: выполняется компиляция ссылки на экземпляр шаблон функции "ValueType &get_valueof<const int,int>(PtrType *,ValueType &)" with [ ValueType=int, PtrType=const int ] [attach=#0][/attach] |
Сообщ.
#8
,
|
|
|
Небольшой оффтоп
Да, я как все, люблю красивый и изящный код. Но, последнее время, понял - нужно бороться с внутренним перфекционизмом! Ибо встают вопросы: 1) ты трудяга-кодер, или 2) ты |
Сообщ.
#9
,
|
|
|
Цитата Eric-S @ Может быть так?Дополнительно, было бы очень хорошо, если бы get_valueof, кроме простых указателей, могла бы работать с умными указателями. Там я думал использовать pointer_traits::element_type для типа возвращаемого значения. template< typename PtrType , typename ValueType> auto get_valueof( PtrType ptr, ValueType& value ) -> typename std::remove_pointer<PtrType>::type& { if constexpr ( std::is_pointer<PtrType>::value) { if (nullptr == ptr ) return value; } if constexpr ( std::is_class<PtrType>::value) { if (nullptr == ptr.get()) return value; } return *ptr; } |
Сообщ.
#10
,
|
|
|
Цитата Majestio @ просто бы твой макро оформил функцией, желательно inline. А сэкономленное время направил бы в другой поток. А вот просто не получается. Он же не только с int работает. |
Сообщ.
#11
,
|
|
|
Цитата Eric-S @ Ну так и правильно делает. Ты исходно константный объект возвращаешь по неконстантной ссылке. Visual studio 2022 std==c++20 выдаёт: |
Сообщ.
#12
,
|
|
|
Цитата Eric-S @ невозможно преобразовать "PtrType" в "ValueType &" Если ты точно знаешь, что ты делаешь - возьми и примени union_cast. Qraizer, при необходимости, раскидает детали. |
Сообщ.
#13
,
|
|
|
Цитата Qraizer @ Хотя да, для умных поинтеров "typename std::remove_pointer<PtrType>::type&" не сработает. Но ты справишься, я уверен . Может быть так? |
Сообщ.
#14
,
|
|
|
Цитата Qraizer @ Может быть так? Тоже ругается: Цитата main.cpp(15): error C2440: return: невозможно преобразовать "ValueType" в "int &" with [ ValueType=const int ] main.cpp(15): note: В результате преобразования теряются квалификаторы main.cpp(63): note: выполняется компиляция ссылки на экземпляр шаблон функции "int &get_valueof<int*,const int>(PtrType,ValueType &)" with [ PtrType=int *, ValueType=const int ] main.cpp(14): warning C4390: ";": обнаружен пустой контролируемый оператор; это правильно? Добавлено Цитата Qraizer @ Ну так и правильно делает. Ты исходно константный объект возвращаешь по неконстантной ссылке. Это как раз понятно. И я указал, что это одна из проблем. Пробовал делать перегрузку. Первый вариант, возвращает константную ссылку, а второй вариант неконстантную ссылку. Но компилятор не может выбрать нужную перегрузку. Прикреплённый файлmain.zip (694 байт, скачиваний: 52) |
Сообщ.
#15
,
|
|
|
Цитата Eric-S @ Думаю, с этим и не надо бороться. Ты ж сам захотел ссылку возвращать. Если в качестве value по умолчанию в точке вызова кто-то подставит const, ССЗБ. Пробовал делать перегрузку. Первый вариант, возвращает константную ссылку, а второй вариант неконстантную ссылку. Но компилятор не может выбрать нужную перегрузку. |