Сравнение всегда ложно из-за ограниченного диапазона ... с шаблонами - PullRequest
6 голосов
/ 13 января 2010

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

Я использую g ++ в Linux, и я предполагаю, что есть способ подавить это конкретное предупреждение с помощью параметра командной строки для g ++, но я все же хотел бы получить предупреждение в других, не шаблонных случаях. Мне интересно, есть ли в коде какой-нибудь способ предотвратить это без необходимости написания нескольких версий функции?

template < class T >
T trim(T &val)
{
  if (val < 0)
  {
    val = 0;
  }
  return (val);
}
int main()
{
  char cval = 5;
  unsigned char ucval = 5;

  cout << "Untrimmed: " << (int)cval;
  cval = trim(cval);
  cout << " Trimmed: " << (int)cval << endl;

  cout << "Untrimmed: " << (int)ucval;
  cval = trim(ucval);
  cout << " Trimmed: " << (int)ucval << endl;

 return (0);
}

Ответы [ 4 ]

6 голосов
/ 13 января 2010
#include <algorithm>

template<class T>
T& trim(T& val) {
  val = std::max(T(0), val);
  return val;
}

Из вопроса не очевидно, что передача по неконстантной ссылке уместна. Вы можете изменить вышеуказанное, ничего не возвращая (void), передавая по значению и возвращая по значению, или передавая по const & и возвращая по значению:

template<class T>
T trim(T const& val);

// example use:
value = trim(value); // likely the most clear solution

Обобщите немного больше, хотя и выходите за рамки вашего вопроса:

template<class T>
T constrain(T const& value, T const& lower, T const& upper) {
  // returns value if value within [lower, upper] (inclusive end points)
  // returns lower if value < lower
  // otherwise returns upper
  assert(lower <= upper); // precondition
  return std::min(std::max(value, lower), upper);
}

template<class T>
T constrain_range(T const& value, T const& lower, T const& upper) {
  // returns value if value within [lower, upper) (exclusive upper)
  // returns lower if value < lower
  // otherwise returns upper - 1
  assert(lower < upper); // precondition
  if      (value <  lower) return lower;
  else if (value >= upper) return upper - 1;
  else                     return value;
}
5 голосов
/ 13 января 2010

Для представленного простого случая вам, безусловно, будет лучше решение, представленное Roger Pate .

Для общего решения метапрограммирования вам нужно: type_traits . Вы можете использовать либо те, что от Boost, либо те, которые поставляются с вашим STL, если они достаточно современны.

namespace detail {

  template < class T >
  T trim_impl(T &val, const std::tr1::true_type& )
  {
    if (val < 0)
    {
      val = 0;
    }
    return (val);
  }

  template < class T >
  T trim_impl(T &val, const std::tr1::false_type& )
  {
    return (val);
  }  

} // end namespace detail

template < class T >
T trim(T &val)
{
  return detail::trim_impl( val, std::tr1::is_signed<T>() );
}

Обратите внимание, что is_signed равно false_type для чисел с плавающей запятой (не спрашивайте, почему). Чтобы приведенный выше код работал с плавающими точками, вам необходимо ввести другую черту, например

typedef std::tr1::integral_constant< bool, 
            std::tr1::is_signed<T>::value || 
            std::tr1::is_floating_point<T>::value > has_sign;

... и да, чем глубже вы погружаетесь в метапрограммирование , тем страшнее оно становится ... пренебрегайте этим решением и используйте простое, перечисленное Роджером: P.

2 голосов
/ 06 января 2011

Флаг компилятора для подавления предупреждения: -Wno-type-limits для gcc.

1 голос
/ 28 декабря 2011

Все типы предупреждений -Wtype-limit могут подавляться в каждом конкретном случае путем преобразования каждого сравнения, генерирующего предупреждение, в фиктивную функцию, которая принимает оба операнда, использованных в сравнении, и возвращает результат сравнения операндов. Например, функцию trim () из исходного вопроса можно преобразовать в:

// Dummy function for -Wtype-limits warnings suppression.
template < class T >
static inline dummy_less(const T &a, const T &b)
{
  return (a < b);
}

template < class T >
T trim(T &val)
{
  if (dumy_less(val, 0))
  {
    val = 0;
  }
  return (val);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...