Как заставить Clang игнорировать конкретное предупреждение в конкретном блоке?

Я проверяю числовой диапазон значений с типом признаков, а неподписанные типы генерируют предупреждение.

Comparison of unsigned expression >= 0 is always true

Как отключить некоторое предупреждение в определенном диапазоне кода? Я использовал стиль GCC #pragma с Clang, но это не работает. Вот мой код.

template<typename originT, typename destinationT>
void
assertForNumericRange(const originT value)
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored  "-Wtype-limits"
    assertWithReason(value >= std::numeric_limits<destinationT>::min());
    assertWithReason(value <= std::numeric_limits<destinationT>::max());
#pragma GCC diagnostic pop
}

Примечание

В настоящее время я разделил это утверждение на три группы: с плавающей запятой, unsigned int, signed int. Но я хочу объединить их в один, если это возможно.

Я использую Xcode 5.0 beta. В командной строке он сообщает об этом: Версия Apple LLVM

5.0 (clang-500.1.58) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin12.3.0
Thread model: posix

Ответы

Ответ 1

Какую версию Clang вы используете? Из Руководство пользователя Clang оно должно работать так же, как и вы. Но ваши утверждения диапазона не будут работать так, как вы, вероятно, хотите, чтобы они работали:

Это первое утверждение само по себе не имеет большого смысла, если destinationT не имеет знака, поэтому min дает 0. Либо originT тоже без знака, то он явно не отрицательный, о чем компилятор предупреждает вас. Или originT подписывается, сравнение будет конвертировать один или оба операнда в другие типы, например. возможно преобразование value в беззнаковое (и, следовательно, положительное) представление.

Рассмотрим, например,

 assertForNumericRange<signed char, unsigned long>( (signed char)-1);  

Сравнение между (signed char)-1 и unsigned long будет продвигать -1 до unsigned long, эффективно давая следующие утверждения для 32-битной длины:

assertWithReason((unsigned long)0xFFFFFFFF >= std::numeric_limits<destinationT>::min());
assertWithReason((unsigned long)0xFFFFFFFF <= std::numeric_limits<destinationT>::max());

Оба сравнения дадут true, а -1 явно не находится в диапазоне значений unsigned long.

Ответ 2

Прежде всего, имейте в виду, что:

std::numeric_limits<float>::min()

будет возвращать ноль, так как

std::numeric_limits<T>::min()

возвращает наименьшее не положительное число для целых типов, наименьшее не отрицательное число для типа с плавающей точкой

Минимальное отрицательное число для типа с плавающей запятой:

-std::numeric_limits<T>::max()

Я думаю, вам нужно объединить разные numeric_limits methods/members (например, is_integer и is_signed) и операторы if, а также получить избавиться от ваших предупреждений. (С точки зрения эффективности) Вам не нужно беспокоиться о том, чтобы получить слишком сложную функцию, так как большая часть проверок будет оцениваться во время компиляции и не будет влиять на время выполнения. Фактически, если вы можете избежать некоторых ненужных проверок во время выполнения из-за некоторых проверок, выполненных во время компиляции, ваша программа будет быстрее.

Вы также должны использовать std::is_same<T,U>::value и избегать дальнейшей проверки, если это правда.