На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
> перегрузка шаблонной функции
    Здравствуйте!

    Вроде бы банальность, но я запутался или чего-то не понимаю.

    Требуется шаблон функции get_valueof, которая разыменовывает указатель, а если же он нулевой, то возвращает значение по умолчанию. Алгоритм простейший.
    ExpandedWrap disabled
      template< typename ValueType >
      auto get_valueof( ValueType*ptr, ValueType& value ) -> ValueType&
      {
      if( nullptr == ptr )
          return value;
      else
          return *ptr;
      }


    Ссылочность возвращаемого значения и значения по умолчанию желательна, чтобы не копировать толстые объекты. И вот тут начинаются трудности. А ещё с модификатором константности. Компилятор путается и не знает, какие подставить шаблонные параметры. А если перегружаю функцию, то он не может выбрать наиболее подходящий вариант.
    Сделал простенькие тесты, для четырёх вариантов, которые у меня не проходят.
    ExpandedWrap disabled
      //  разыменование константного  указателя и константного значения
      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 для типа возвращаемого значения. Наверное, он и для обычного указателя сгодится. Но чего-то у меня не стыкуется.
      Eric-S, я разделяю твою озабоченность в данном вопросе. что ответить, пока не знаю.
      Но, прошу рассказать про практическую ценность вопроса, примеры предполагаемого применения.
      Просто для предварительной "ориентации".
        Eric-S, зачем за компилятор делать то, что он и сам умеет?
        ExpandedWrap disabled
          template< typename PtrType , typename ValueType>
          auto get_valueof( PtrType*ptr, ValueType& value ) -> ValueType&
        Пусть сам проверяет возможность вернуть value через тип *ptr
          Цитата Majestio @
          прошу рассказать про практическую ценность вопроса, примеры предполагаемого применения.
          Просто для предварительной "ориентации".

          В нулевых, делаю рефакторинг старого кода, а там примерно тследующий макрос:
          ExpandedWrap disabled
            #define get_pointerof( ptr, value ) (( nullptr == (ptr))? (value): (*ptr))

          Но макросы это зло, которые нужно постаратся заменить шаблонными функциями.

          Во-первых, синтаксический сахар, для сокращения или упращения кода.
          ExpandedWrap disabled
            void callback_proc( const int*const data )
            {
            std::cout << "data=" << get_valueof( data, 0 ) << std::endl;
            }

          Это особо актуально, когда получаются длинные функции, на стыке C++ и разных API в стиле языка C.

          Забавно, что изначально думается, будто бы подобных ситуаций мало. Ну, их действительно не много, особенно в проектах написанных по феншую. Но всё же иногда возникает нужда применить в самых неожиданных местах. Так что пусть будет, для наглядности.

          Во-вторых, ради симетрии. У меня используется функция set_valueof. Она, тоже для сахара, слегка упращает жизнь.
          ExpandedWrap disabled
            void callback_proc( const int category, int*const result )
            {
            switch( category )
            {
             
            case 1:
            set_valueof( result, 1 );
             
            default:
            set_valueof( result, 0 );
             
            }
            }

          Лениво писать одни и те же условия по несколько раз, раздувая код. Сокращение минимально, но оно всё же есть .

          В-третьих, собственно get_valueof, простой пример функции, код которой можно выложить на форуме, чтобы продемонстрировать возникшие затруднения.
          Мне же хочется понять суть проблемы и способ её решения, чтобы использовать для других, более сложных функций.
          А это всего лишь подопытный котёнок, на котором можно экспериментировать.
            Хотя логичнее всё ж
            ExpandedWrap disabled
              auto get_valueof( PtrType*ptr, ValueType& value ) -> PtrType&
            Как-никак ValueType – это затычка, а основной тип PtrType, как ни крути
              Цитата Eric-S @
              В нулевых, делаю рефакторинг старого кода, а там примерно тследующий макрос:

              Ну не знаю. Я тоже всегда за фэн-шуй топлю, но, в твоем случае, я просто бы твой макро оформил функцией, желательно inline. А сэкономленное время направил бы в другой поток.
                Цитата 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]
                Сообщение отредактировано: Eric-S -
                  Небольшой оффтоп

                  Да, я как все, люблю красивый и изящный код. Но, последнее время, понял - нужно бороться с внутренним перфекционизмом! Ибо встают вопросы: 1) ты трудяга-кодер, или 2) ты музыкальный программистский критик. Первых уважаю, вторых - терплю, чисто ИМХО.
                    Цитата Eric-S @
                    Дополнительно, было бы очень хорошо, если бы get_valueof, кроме простых указателей, могла бы работать с умными указателями. Там я думал использовать pointer_traits::element_type для типа возвращаемого значения.
                    Может быть так?
                    ExpandedWrap disabled
                      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;
                      }
                      Цитата Majestio @
                      просто бы твой макро оформил функцией, желательно inline. А сэкономленное время направил бы в другой поток.

                      А вот просто не получается. Он же не только с int работает.
                        Цитата Eric-S @
                        Visual studio 2022 std==c++20 выдаёт:
                        Ну так и правильно делает. Ты исходно константный объект возвращаешь по неконстантной ссылке.
                          Цитата Eric-S @
                          невозможно преобразовать "PtrType" в "ValueType &"

                          Если ты точно знаешь, что ты делаешь - возьми и примени union_cast. Qraizer, при необходимости, раскидает детали.
                            Цитата Qraizer @
                            Может быть так?
                            Хотя да, для умных поинтеров "typename std::remove_pointer<PtrType>::type&" не сработает. Но ты справишься, я уверен ;) .
                              Цитата 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)
                                Цитата Eric-S @
                                Пробовал делать перегрузку. Первый вариант, возвращает константную ссылку, а второй вариант неконстантную ссылку. Но компилятор не может выбрать нужную перегрузку.
                                Думаю, с этим и не надо бороться. Ты ж сам захотел ссылку возвращать. Если в качестве value по умолчанию в точке вызова кто-то подставит const, ССЗБ.
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0419 ]   [ 18 queries used ]   [ Generated: 12.09.24, 23:08 GMT ]