2010-06-29 3 views
5

У меня возникли проблемы, которые я уверен, что это легко исправить, но я в растерянности ...Закрепление «Сравнение всегда ложно ...» предупреждение в GCC

У меня есть шаблон, выполняет следующий код:

T value  = d; 
if (std::numeric_limits<T>::is_signed) 
{ 
    if (value < 0) 
    { 
     *this += _T("-"); 
     value = -(signed)value; 
    } 
} 

Теперь, очевидные причины, GCC дает мне предупреждение (сравнения всегда ложно из-за ограниченный диапазон типа данных), когда этот код компилируются для неподписанного типа. Я полностью понимаю аргументы позади этого, и я ввел проверку numeric_limits, чтобы узнать, могу ли я заставить компилятор заткнуться (он работал для MSVC). Увы, в GCC я получаю предупреждение. Есть ли способ (если не отключить предупреждение, которое я даже не знаю, если вы можете сделать с GCC), чтобы исправить это предупреждение? Код никогда не будет вызван в любом случае, и я бы предположил, что оптимизатор тоже его скомпилирует, но я не могу избавиться от предупреждения.

Может ли кто-нибудь дать мне решение?

Cheers!

+2

Это ОЧЕНЬ неприятно, когда 'int' - 16 бит. Когда 'value' является длинным, значение value = - (signed/* int * /) усекает большие значения. Умножьте на '-1' вместо этого, и пусть оптимизатор это выяснит. – MSalters

ответ

5

простое решение:

template <typename T> inline bool isNegative(T value) { 
    return std::numeric_limits<T>::is_signed && value < 0; // Doesn't trigger warning. 
} 

T value  = d; 
if (isNegative(value)) // Doesn't trigger warning either. 
{ 
    *this += _T("-"); 
    value = -1 * value; 
} 
+0

К сожалению, в то время как это исправляет предупреждение gcc, оно вводит новое предупреждение в MSVC, потому что 'isNegative' никогда не использует параметр' value' при вызове с неподписанным типом '(предупреждение C4100: 'value': unreferenced formal parameter)'. Удовлетворение каждого компилятора затруднено - возможно, было бы лучше отключить предупреждение, чем писать код, который компилируется абсолютно везде. –

+0

Чтобы расширить это; Я думаю, что каждое найденное вами решение либо вызовет предупреждение компилятора, либо будет содержать запутанную логику, которую будет сложнее поддерживать. –

+0

Я полагаю, что обертка 'std :: numeric_limits :: is_signed' в шаблоне функции может удалить предупреждение:' template bool is_signed (const T &) {return std :: numeric_limits :: is_signed;} '- однако, если он делает это, он (как версия MSalters) делает это __at стоимостью включения проверки времени компиляции во время проверки. В конце концов я бы, вероятно, отключил предупреждение в VC ('#pragma warn (push: 4100)', IIRC) прямо перед оскорбительной строкой и снова включил его ('#pragma warn (pop)'). – sbi

3

Может ли кто-нибудь дать мне решение?

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

//Beware, brain-compiled code ahead! 
template< bool B > 
struct Bool { const static bool result = B; } 

template< typename T > 
void do_it(T& , Bool<false> /*is_signed*/) 
{ 
    // nothing to do for unsigned types 
} 

template< typename T > 
void do_it(T& value, Bool<true> /*is_signed*/) 
{ 
    if (value < 0) { 
     *this += _T("-"); 
     value = -(signed)value; 
    } 
} 

template< typename T > 
void do_something(T& value) 
{ 
    do_it(value, Bool<std::numeric_limits<T>::is_signed>()); 
} 

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

+0

Немного overcomplicated - введение компиляции обертки времени вокруг bool и дополнительный параметр для вызова? Кроме того, значение 'value' должно быть передано с помощью неконстантной ссылки, поскольку его значение изменяется. Поскольку он использует 'this',' T', вероятно, является параметром шаблона класса, а не функцией. –

+0

Когда я прокомментировал, ваше решение не будет компилироваться, потому что вы используете ссылку на const для измененного значения. Извините, если вы это понимаете, поскольку мое «раздражение» с вами. Вы также можете заметить, что я не проголосовал за ваш ответ. Редактирование, которое я сделал в своем комментарии, заключалось в том, чтобы добавить последнее предложение. –

+0

@Joe: Тогда я должен был неправильно прочитать ваш комментарий, и я приношу свои извинения за свой ответ. Я удалил свой комментарий. (Ваш комментарий совпал с тем, что позже оказалось удаленным голосованием, BTW, который сначала я принимал как проголосовавший.) В любом случае, в отношении типа «Bool <>»: я бы не мечтал пробовать код C++ без этого в моей панели инструментов. Это всегда есть, и мне просто нужно схватить его, когда мне это нужно.':)' – sbi

2

Вы можете специализироваться вашу функцию как это:

template <bool S> 
void manipulate_sign(T&) {} 

template <> 
void manipulate_sign<true>(T& value) { 
    if (value < 0) 
    { 
    *this += _T("-"); 
    value = -(signed)value; 
    } 
} 

//then call like this: 
manipulate_sign<std::numeric_limits<T>::is_signed>(); 

Просто отключить предупреждение может быть лучше, хотя.

+1

Я бы определенно обернул эту функцию, поэтому пользователю не нужно использовать 'numeric_limits' сам -' T' - это вся информация, которая нужна функции :) –

3

См https://stackoverflow.com/a/8658004/274937 для реального решения, которое позволяет подавляя -Wtype-пределы предупреждения от случая к случаю. Короче говоря, просто оберните каждое сравнение, которое генерирует предупреждение, в фиктивную функцию.

 Смежные вопросы

  • Нет связанных вопросов^_^