Можно ли избежать ошибок в частях шаблонной функции c ++, которые не будут выполняться в конце? - PullRequest
1 голос
/ 07 мая 2019

У меня есть шаблон с двумя целыми числами в качестве входных данных.Один может иметь больший тип, чем другой.Мой код выполняет смещение соответственно, так что результаты соответствуют типу назначения .

Вот основная идея функции:

template<typename S, typename D>
D convert(S a)
{
     return static_cast<D>(a);
}

Когда размер между S и D меняется, хотя я хочу сместить значение.Поэтому я добавляю пару условий:

    if(sizeof(S) < sizeof(D))
    {
        return a << (sizeof(D) - sizeof(S)) * 8;
    }

    if(sizeof(S) > sizeof(D))
    {
        return a >> (sizeof(S) - sizeof(D)) * 8;
    }

Проблема в том, что я получаю следующие ошибки:

conversions.cpp: В экземпляре 'void convert (buffer_ &) [withS = беззнаковый символ;D = короткое без знака int;buffer_t = std :: vector] ':
conversions.cpp: необходимо отсюда
conversions.cpp: ошибка: счетчик смещения вправо> = ширина типа [-Werror = shift-count-overflow]

  d[idx] = convert_sign<S, D>(static_cast<std::int64_t>(s[idx]) >> (sizeof(S) - sizeof(D)) * 8);

_Примечание: для тех, кто не понимает, (sizeof(S) - sizeof(D)) или (sizeof(D) - sizeof(S)) в блоке неправильный if() будет отрицательным и, следовательно,рассматривается как действительно большой параметр сдвига (поскольку параметры сдвига принимаются как значения без знака, он очень большой и не отрицательный, в любом случае sizeof() возвращает std::size_t, что без знака.)

Очевидно, яможно использовать прагму, чтобы игнорировать предупреждение и покончить с ним.

Однако я ожидал, что if() с false просто не будет скомпилирован, поэтому с тех пор ошибок не будетпроисходит во время компиляции (т.е. компилятор знает, будет ли выполняться блок if() во время его компиляции.) Есть ли способ не использовать прагму и все же избежать ошибки?

1 Ответ

4 голосов
/ 07 мая 2019

Однако я ожидал, что if (), который имеет false, просто не будет скомпилирован, поэтому не будет ошибок, так как это происходит во время компиляции (то есть компилятор знает, будет ли выполнен блок if () или не во время компиляции.)

Вы описываете поведение if constexpr, которое, к сожалению, доступно только начиная с C ++ 17

Когда вы пишете

if constexpr ( some_compile_time_test )
   some_code_1;
else
   some_code_2;

где some_compile_time_test - это тест, который может быть определен во время компиляции (как sizeof(S) < sizeof(D)), компилятор компилирует some_code_1 - и полностью игнорирует some_code_2 - когда тест равен true и наоборот в противном случае

Если вы только напишите

if ( some_test )
   some_code_1;
else
   some_code_2;

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

До C ++ 17 (в основном, но не только, C ++ 11 и C ++ 14) вам необходимо разработать две (или более) различных функций / методов.

Найдите «SFINAE» и «Диспетчеризация тегов», чтобы увидеть пару полезных методов.

Пример СФИНАЕ

template <typename S, typename D>
typename std::enable_if<(sizeof(S)<sizeof(D)), S>::type convert (S a)
 { return a << (sizeof(D) - sizeof(S)) * 8; }

template <typename S, typename D>
typename std::enable_if<(sizeof(S)>sizeof(D)), S>::type convert (S a)
 { return a >> (sizeof(S) - sizeof(D)) * 8; }

и пример рассылки тегов (осторожно для обоих: код не проверен)

template <typename S, typename D>
S convert (S a, std::true_type)
 { return a << (sizeof(D) - sizeof(S)) * 8; }

template <typename S, typename D>
S convert (S a, std::false_type)
 { return a >> (sizeof(S) - sizeof(D)) * 8; }

template <typename S, typename D>
S convert (S a)
 { return convert<S, D>(a, std::integral_constant<bool, (sizeof(S)<sizeof(D))>{}); }
...