Как написать n-арный отрицатель?

Полезность унарных и бинарных отрицателей легко понять.

Пример с унарным отрицателем (not1):

class Even
{
public:
bool operator() (const int& x) const { return x % 2 == 0; }
typedef int argument_type;
};

int values[] = { 9, 1, 8, 2, 7, 3, 6, 4, 5 };

int even = count_if(values, values + 9, Even());
int odd = count_if(values, values + 9, not1(Even())); // <= unary negator
cout << "We have " << even << " even elements in the array.\n";
cout << "We have " << odd  << " odd elements in the array.\n";

Выход:

We have 4 even elements in the array.
We have 5 odd elements in the array.

Пример с бинарным отрицателем (not2):

int values[] = { 9, 1, 8, 2, 7, 3, 6, 4, 5 };

// original array
for (int i : values)
cout << i << " ";
cout << "\n";// array in ascending order
sort(values, values + 9, less<int>());

for (int i : values)
cout << i << " ";
cout << "\n";

// array in descending order
sort(values, values + 9, not2(less<int>())); // <= binary negator

for (int i : values)
cout << i << " ";
cout << "\n\n";

Выход:

9 1 8 2 7 3 6 4 5
1 2 3 4 5 6 7 8 9
9 8 7 6 5 4 3 2 1

Как насчет n-арных отрицателей (not3, not4, not5 … notn)

Давайте предположим, что мне нужно посчитать количество элементов, которые не между два числа (нижний предел и верхний предел) в коллекции (возможно, массив).

.

int elems_betweem = count_if(values, values + n, not3(bind(Between<int>(), _1, lowerValue, upperValue)));

.

Как мне написать not3 инвертор?

Более того, у нас есть общий not как заменитель not1 а также not2 так же, как bind против bind1st а также bind2nd ?

Спасибо

0

Решение

Начиная с C ++ 17 станд :: not_fn будет доступно:

auto between = [](int value, int lowerValue, int upperValue) {
return lowerValue < value && value < upperValue;
};

int elems_between = std::count_if(std::cbegin(values), std::cend(values),
std::bind(std::not_fn(between), std::placeholders::_1, lowerValue, upperValue));

пример wandbox

1

Другие решения

Как написать отрицатель not3?

Пример, совместимый с C ++ 03:

template<class Pred>
class ternary_predicate {
Pred pred;
public:
ternary_predicate(Pred pred): pred(pred){}

template<class A, class B, class C>
bool
operator()(A const& a, B const& b, C const& c) const {
return !pred(a, b, c);
}
};

template<class Pred>
ternary_predicate<Pred>
not3(Pred pred) {
return ternary_predicate<Pred>(pred);
}

Более того, у нас есть универсальный не как заменитель not1 и not2 так же, как bind vs bind1st и bind2nd?

Мы сделаем, как только C ++ 17 станет официальным. Предлагается ввести std::not_fn в качестве замены std::not1 а также std::not2 который затем будет объявлен устаревшим.

Если вы чувствуете нетерпение, вам не составит труда реализовать себя в C ++ 14:

template<class Pred>
auto
not_fn(Pred&& pred) {
return [pred=std::forward<Pred>(pred)](auto&&... args){
return !pred(std::forward<decltype(args)>(args)...);
};
}
0

Вы можете написать свой собственный std::not_fn пока это не доступно:

template <typename T>
struct not_func
{
template <typename...Args>
constexpr bool operator()(const Args&...args) const { return !T{}(args...); }
};

Пример использования:

int main()
{

bool a1 = std::less<int>{}(1, 2);
bool a2 = not_func<std::less<int>>{}(1, 2);

bool b1 = Even{}(1);
bool b2 = not_func<Even>{}(1);std::cout
<< "a1 = " << (a1 ? "true" : "false") << "\n"<< "a2 = " << (a2 ? "true" : "false") << "\n"<< "b1 = " << (b1 ? "true" : "false") << "\n"<< "b2 = " << (b2 ? "true" : "false") << "\n";
}
[На колиру] [На Годболте]

Я не проверил все возможные варианты, так что это может быть ошибкой.

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector