Сравнение всегда является ложью из-за ограниченного диапазона … с шаблонами

У меня есть шаблонная функция, которая воздействует на шаблонную переменную типа, и если значение - меньше чем 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);
}
6
задан jww 6 July 2015 в 08:24
поделиться

2 ответа

#include <algorithm>

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

Это не очевидно из вопроса, который передает ссылку без постоянного. Вы можете изменить вышеупомянутое возвращение ничего (пустота), пропустите по значению и возврату по значению, или пройдите по 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;
}
6
ответ дан 8 December 2019 в 17:21
поделиться

Для чтения файлов свойств в Groovy можно использовать служебный класс ConfigSlupper и обращаться к содержащимся свойствам с помощью выражений GPath. Однако необходимо помнить, что ConfigSluper не поддерживает стандартные файлы свойств Java. Как правило, ConfigSluper используется для чтения файлов с расширением groovy, которые могут быть похожи на файл свойств, но придерживаться стандартной записи groovy, таким образом, Последовательности находятся внутри кавычек и комментариев, начинающихся с // или находятся внутри блока /* */. Таким образом, для чтения файла свойств Java необходимо создать объект java.util.Properties и использовать его для создания ConfigStulper :

def props = new Properties()
new File("message.properties").withInputStream { 
  stream -> props.load(stream) 
}
// accessing the property from Properties object using Groovy's map notation
println "capacity.created=" + props["capacity.created"]

def config = new ConfigSlurper().parse(props)
// accessing the property from ConfigSlurper object using GPath expression
println "capacity.created=" + config.capacity.created

Если используется только файл свойств из кода Groovy, следует использовать непосредственно вариант обозначения Groovy.

def config = new ConfigSlurper().parse(new File("message.groovy").toURL())

Это также дает вам некоторые хорошие преимущества по сравнению со стандартными файлами свойств, например, вместо

capacity.created="x"
capacity.modified="y"

вы можете написать

capacity {
  created="x"
  modified="y"
}
-121--1275298-

Под поверхностью, два подхода эквивалентны. Тем не менее, вы получаете большинство стандартных преимуществ OO при использовании класса: инкапсуляция, наследование и т.д.

Также, посмотрите на следующие примеры:

$arr['naem'] = 'John';

является совершенно действительным и может быть трудной ошибки найти.

С другой стороны,

$class->setNaem('John');

никогда не сработает.

-121--1242901-

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

Для общего решения метапрограммирования требуется тип _ характеристики . Вы можете использовать либо от 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>() );
}

Обратите внимание, что _ подписывается имеет false _ type для плавающих точек чисел (не спрашивайте почему). Чтобы вышеупомянутый код работал с плавающими точками, нужно набрать другую черту, например

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

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

5
ответ дан 8 December 2019 в 17:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: