2017-01-23 3 views
0

Die Nützlichkeit von unären und binären Negatoren ist leicht verständlich.Wie schreibe ich einen n-ary Negator?

Beispiel mit unären Negator (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"; 

Output:

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

Beispiel mit binären Negator (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"; 

Ausgang:

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 

Was ist n-ary Negatoren (NOT3, NOT4, not5 ... nichtn)?

Angenommen, ich muss die Anzahl der Elemente zählen, die nicht zwischen zwei Zahlen (untere Grenze und obere Grenze) in einer Sammlung (möglicherweise ein Array) zählen.

. 

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

. 

Wie schreibe ich die NOT3 negator?

Noch mehr, machen wir eine generische not als Ersatzstoff von not1 und not2 in der gleichen Weise wie bind vs bind1st und bind2nd haben?

Danke

+2

Sie brauchen nicht 'not3' here -' bind (Zwischen (), _1, lowerValue, obererWert) 'erstellt einen unären Operator, Sie brauchen also einfach ein' not1'. – Holt

+1

C++ 17 wird vorgeschlagen, einzuführen: 'std :: not_fn', die für jede Arity funktionieren würde. – user2079303

+0

In Ihrem Beispiel benötigen Sie 'not1' und nicht' not3'. Der Rückgabewert von 'bind (Between (), _1, lowerValue, obererValue)' ist ein Callable unter Verwendung eines Parameters und nicht 3. –

Antwort

1

Da C++ 17 std::not_fn verfügbar sein:

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 example

+0

BRILLIANT !!! Sie beantworten die Frage und schreiben ein Arbeitsbeispiel in eine zukünftige Version von C++. Jeden Tag liebe ich C++ mehr und mehr! Gott verdammt .NET und Java! – user7140484

0

Wie schreibe ich die NOT3 negator?

A C 03 ++ konform Beispiel:

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); 
} 

Noch mehr, haben wir eine generische nicht als Ersatzstoff von not1 und not2 in der gleichen Weise wie bind vs bind1st und bind2nd?

Wir werden, sobald C++ 17 ist offiziell. Es wird vorgeschlagen, std::not_fn als Ersatz für std::not1 und std::not2 einzuführen, die dann veraltet sind.

Wenn Sie ungeduldig fühlen, es sollte nicht schwierig sein, sich zu implementieren in 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

Sie können Ihre eigenen schreiben std::not_fn solange es nicht verfügbar ist:

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

Beispiel Nutzung:

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"; 
} 

[On Coliru] [On Godbolt]

Ich habe nicht alle möglichen Varianten getestet, so dass dies immer noch fehlerhaft ist.