У меня есть шаблонная функция, которая воздействует на шаблонную переменную типа, и если значение - меньше чем 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);
}
#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;
}
Для чтения файлов свойств в 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;
... и да, чем глубже вы попадаете в метапрограммирование чем страшнее оно становится так... игнорируйте это решение и переходите к простому, перечисленному Роджером: П.