Изменить операторы сравнения без большого условного блока

Я проверяю, лежит ли число между двумя значениями. Я оставляю на усмотрение пользователя выбор, должно ли логическое сравнение включать equal to в один (или оба) из пределов или нет. Они устанавливают это, определяя struct, который содержит два значения края и какой оператор сравнения использовать:

typedef struct {
    double low; 
    double high;
    bool low_equal; //false if a greater than operator (`>`) should be used, true if a greater-than-or-equal-to (`>=`) operator should be used
    bool high_equal; //Same as low_equal but for a less-than operator
} Edges;

Создается массив Edges (обозначенный ниже bins), и для каждого входа value я проверяю, находится ли он в пределах границ ячейки. Однако, чтобы использовать нужную пару операторов сравнения, я получил этот отвратительный условный блок:

        if (bins[j].low_equal && bins[j].high_equal)
        {
            if (value >= bins[j].low && value <= bins[j].high)
            {
                break;
            }
        }
        else if (bins[j].low_equal)
        {
            if (value >= bins[j].low && value < bins[j].high)
            {
                data[i] = bins[j].value;
                break;
            }
        }
        else if (bins[j].high_equal)
        {
            if (datum > bins[j].low && datum <= bins[j].high)
            {
                break;
            }
        }
        else
        {
            if (value > bins[j].low && value < bins[j].high)
            {
                break;
            }
        }

Есть лучший способ сделать это? Можно ли как-то настроить используемые операторы и потом просто вызывать их?


person jramm    schedule 03.01.2016    source источник
comment
Вы можете использовать std::function и эквиваленты функций оператора, например. std::less, std::less_equal и т. д.   -  person πάντα ῥεῖ    schedule 03.01.2016
comment
@jramm что, если значение соответствует более чем одному элементу в вашем массиве?   -  person Klitos Kyriacou    schedule 03.01.2016


Ответы (3)


Простым подходом может быть:

bool higher = (value > bins[j].low) || (bins[j].low_equal && value == bins[j].low); 
bool lower  = (value < bins[j].high) || (bins[j].high_equal && value == bins[j].high); 

if (higher && lower)
{
    // In range
}
person 4386427    schedule 03.01.2016

вы можете использовать указатель на функцию

bool less(double lhs, double rhs) { return lhs < rhs; }
bool less_or_equal(double lhs, double rhs) { return lhs <= rhs; }
using comp_double = bool(double, double);

а потом

comp_double *low_comp = bins[j].low_equal ? less_or_equal : less;
comp_double *high_comp = bins[j].high_equal ? less_or_equal : less;

if (low_comp(bins[j].low, value) && high_comp(value, bins[j].high)) {
   // In range
}
person Jarod42    schedule 03.01.2016
comment
Не нужно определять что-то вроде less самостоятельно, уже есть стандартные функции std::less и т.д. - person πάντα ῥεῖ; 03.01.2016
comment
Я вижу, это тоже C++14. - person πάντα ῥεῖ; 03.01.2016

Это было бы ИМО хорошим случаем для тернарного оператора

if ((bins[j].low_equal ? bins[j].low <= value : bins[j].low < value) &&
    (bins[j].high_equal ? value <= bins[j].high : value < bins[j].high)) {
   ...
}
person 6502    schedule 03.01.2016