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

    ExpandedWrap disabled
      #include <iostream>
      #include <limits>
       
      using namespace std;
       
      void Test(const uint16_t cho) {
        cout << "Okay: " << cho << endl;
      }
       
      int main() {
          uint64_t blin = std::numeric_limits<uint64_t>::max();
          Test(blin); // <-- ругаться нужно тут
          return 0;
      }
      Ну, самое простое, это
      ExpandedWrap disabled
        template <typename T>
        typename std::enable_if<std::is_same_v<T, uint16_t>, void>::type Test(const T cho) {
          cout << "Okay: " << cho << endl;
        }
      Нынче модно пользовать концепты, но это решение работоспособно и ранее C++20

      Добавлено
      Впрочем, на концептах не сильно-то иначе:
      ExpandedWrap disabled
        template <typename T> requires std::same_as<T, uint16_t>
        void Test(const T cho)
        {
          cout << "Okay: " << cho << endl;
        }
        Т.е. без метапрограммирования никак? Может какие-то ключи компилятора смогут ворнинг на это запилить?
          Может как-то это можно использовать?
          ExpandedWrap disabled
            void test_func(uint8_t arg);
            void test()
            {
                uint64_t i = 0;
                uint8_t test[] = {i};
                test_func(test[0]);
            }
            file.cpp: In function 'void test()':
            file.cpp:28:23: warning: narrowing conversion of 'i' from 'uint64_t' {aka 'long long unsigned int'} to 'uint8_t' {aka 'unsigned char'} [-Wnarrowing]
               28 |     uint8_t test[] = {i};
                  |                       ^
            Цитата Majestio @
            Т.е. без метапрограммирования никак? Может какие-то ключи компилятора смогут ворнинг на это запилить?
            В Стандарте чёрным по-англицки написано:
            Цитата 7.8 Integral conversions
            2 If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2n where n is the number of bits used to represent the unsigned type). [ Note: In a two’s complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation). —end note ]
            3 If the destination type is signed, the value is unchanged if it can be represented in the destination type; otherwise, the value is implementation-defined.

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

            P.S. В документации VS этот ключик даже явно определён как нарушающий Стандарт:
            Цитата
            Because /RTCc rejects code that conforms to the standard, it's not supported by the C++ Standard Library.


            Добавлено
            P.P.S. Метапрограммирование тем и замечательно, что ты волен напрограммить на нём любые дополнительные аспекты, каковые тебе понадобились, если они не выходят за рамки грамматики языка. Так что не стоит его сторониться.
              Цитата Qraizer @
              Т.е. формально для беззнаковых целых задача в принципе нерешаема, для знаковых она зависит от возможностей реализации. Например, в VC есть ключик -RTCc, но это конкретно его фича. Причём работает она даже для беззнаковых. Где-либо ещё её может и не быть или она управляется иначе.

              Да, печалька. Кажется такой простой и очевидный вопрос :-?
                Цитата Qraizer @
                Т.е. формально для беззнаковых целых задача в принципе нерешаема, для знаковых она зависит от возможностей реализации

                И все же бинго, нашёл! :victory:

                При использовании опции компилятора -Wconversion для GCC, компилятор замечает нарушение беспорядка :lol:

                ExpandedWrap disabled
                  main.cpp: In function ‘int main()’:
                  main.cpp:12:10: warning: conversion from ‘uint64_t’ {aka ‘long unsigned int’} to ‘uint16_t’ {aka ‘short unsigned int’} may change value [-Wconversion]
                     12 |     Test(blin); // <-- ругаться нужно тут
                        |          ^~~~

                Qraizer, проверь, пожалуйста, ключики для мелкомягкого компилятора, для моего исходного кода:

                ExpandedWrap disabled
                  cl.exe /W2 /EHsc main.cpp

                Интересно, что твой компилятор найдёт, и что его не устроит.
                  /W3
                    Цитата Qraizer @
                    /W3

                    :good:
                      Если есть желание немного немного помедитировать, я бы предложил посмотреть на это:
                      ExpandedWrap disabled
                        // шаблон для безопасного приведения типов  U => T
                        // контролирует диапазон целевого типа T и бросает исключение в случае его нарушения значением U
                        template <typename T, typename U> struct SafeCast
                        {
                          static T doIt(const U& val)
                          {
                            using     common_type = std::common_type_t<T, U>; // тип, общий для U и T
                            // минимальный максимум для U и T
                            constexpr common_type high= std::min(static_cast<common_type>(std::numeric_limits<T>::max()),
                                                                 static_cast<common_type>(std::numeric_limits<U>::max())),
                            // максимальный минимум для U и T (особая обработка для U и T разной знаковости)
                                                  low = std::is_signed_v<T> == std::is_signed_v<U> ?
                                                                std::max(static_cast<common_type>(std::numeric_limits<T>::min()),
                                                                         static_cast<common_type>(std::numeric_limits<U>::min()))
                                                                                                   : 0;
                            // проверка диапазона
                            if (val > high || val < low)
                              throw std::out_of_range("Value exceeds allowed bounds.");
                            // всё в порядке, каст
                            return static_cast<T>(val);
                          }
                        };
                         
                        /* Безопасный к переполнению каст арифметических типов. */
                        template <typename T, typename U>
                        inline T safe_cast(const U& val)
                        {
                          return SafeCast<T, U>::doIt(val);
                        }
                      Можно обойтись без класса, просто функцией, но тогда сложно предотвратить неявные касты к U при вызове, а они будут сильно мешать. Класс – самое простое решение не позволить никаких неявных кастов.
                        Цитата Qraizer @
                        Если есть желание немного немного помедитировать, я бы предложил посмотреть на это:

                        Ну это, как говорится, сахар из другого варенья ;)

                        Начиная тему, я просто задался вопросом как зачекать такие "скользкие" моменты. Ну а как там решать дальше - дело десятое.
                          Естественно другого. Но тут цимес в том, что чек выполняется не на уровне типов при компиляции, а на уровне значений при выполнении. Это более гибко и возможно более подходит для твоей задачи. Хотя и менее эффективно в плане производительности + исключения ещё ловить.
                            Цитата Qraizer @
                            Это более гибко и возможно более подходит для твоей задачи

                            Не не не, не для моей. Мне наоборот нужно до рантайма получить сведения о потенциальных дырах.
                            0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                            0 пользователей:


                            Рейтинг@Mail.ru
                            [ Script execution time: 0,0457 ]   [ 16 queries used ]   [ Generated: 28.04.24, 14:45 GMT ]