1

Es gibt mehrere verwandte Fragen, z.B. algorithms with multiple (unary) predicates oder multiple predicates in general. Aber sie scheinen den generischen Fall, den ich anstrebe, nicht anzugehen, und die Antworten sind oft veraltet, weil sie sich auf Konstrukte beziehen, die in C++ 11 veraltet sind. Es könnte alles auf herunterkochen, aber ich bin mir nicht sicher, ob es als ein Duplikat betrachtet werden kann.Wie erstellt man eine generische Funktion für die Kombination von binären Prädikaten?

Ich habe versucht, eine Funktion zu erstellen, die zwei beliebige binäre Prädikate (im Sinne von „Typen, die ein Zwei-Argument operator() und gibt ein bool implementieren“) kombiniert. Mein Ziel war es, die Möglichkeit zu haben, Code wie folgt zu schreiben:

auto p0 = somePredicate(); 
auto p1 = someOtherPredicate(); 
auto p2 = evenMorePredicates(); 

auto combined = and(p0, or(p1, p2)); 

Ich weiß, dass etwas Ähnliches kann mit lambdas erreicht werden (wie auch in der Antwort auf eine der Fragen oben verlinkten vorgeschlagen), aber dies erfordert die Argumenttypen, die im Lambda selbst wiederholt werden sollen. Ich würde gerne wissen, wie eine solche and oder or Funktion wirklich implementiert werden könnte generisch - insbesondere für binäre Prädikate mit beliebigen Argumenttypen.

Mein grundlegender Ansatz (und ein eindruck Beispiel) ist der folgende:

#include <functional> 
#include <iostream> 

template <typename A, typename B, typename P0, typename P1> 
std::function<bool(const A&, const B&)> and(
    const P0& p0, const P1& p1) 
{ 
    return [p0, p1](const A& a, const B& b) 
    { 
     return p0(a, b) && p1(a, b); 
    }; 
} 

int main(int argc, char* argv[]) 
{ 
    auto p0 = [](const int& a, const int& b) 
    { 
     return a < 0 && b > 0; 
    }; 
    auto p1 = [](const int& a, const int& b) 
    { 
     return a < 1 && b > 4; 
    }; 

    // This is what I want: 
    //auto combined = and(p0, p1); 

    // This works, but ... 
    auto combined = and<int, int, std::function<bool(const int&, const int&)>, std::function<bool(const int&, const int&)>>(p0, p1); 

    std::cout << "combined(-3,7) : " << combined(-3, 7) << std::endl; 
    std::cout << "combined(-3,1) : " << combined(-3, 1) << std::endl; 

    return 0; 
} 

In jedem Fall ist das Problem, dass die Template-Parameter der Argumenttypen zu sein scheint, können nicht an der Aufrufstelle abgeleitet werden. Ich habe versucht, Variationen davon, basierend auf anderen verwandten Fragen hier auf Stackoverflow, aber ohne Erfolg. Mein Bauchgefühl ist, dass es dafür eine (einfache) Lösung geben muss, die einige Einschränkungen des Typ-Deduktionssystems von Lambda umgeht, aber ich habe offensichtlich noch nicht den richtigen Weg gefunden.

+0

Sie könnten einfach 'pred_and (p0, p1)'. Beachten Sie, dass 'und' ein reserviertes Wort ist. – TartanLlama

+1

Das Ableiten der Parametertypen für den zurückgegebenen Abschluss ist im generischen Fall nicht wirklich möglich. Was, wenn Ihr Prädikat ein generisches Lambda oder eine Funktion mit mehreren 'operator()' Überladungen ist? – TartanLlama

+3

können Sie [C++ 14] (http://coliru.stacked-crooked.com/a/d9329a693b80f4ed) verwenden? –

Antwort

2

Sie könnten einen Funktor Klasse schreiben Sie Ihren Ausdruck zu tragen:

template <typename P0, typename P1> 
class AndFunctor { 
public: 
    AndFunctor (P0 p0, P1 p1) 
    : m_p0{std::move(p0)}, m_p1{p1} 
    {} 

    template <typename T, typename U> 
    bool operator() (T&& t, U&& u) { 
     return m_p0(t, u) && m_p1(t, u); 
    } 

private: 
    P0 m_p0; 
    P1 m_p1; 
}; 

Dann eine Instanz zurückkommen in Ihrer and Funktion (and ein Schlüsselwort ist, so dass dieser Code benennt sie in and_p

template <typename P0, typename P1> 
AndFunctor<P0,P1> and_p(P0 p0, P1 p1) 
{ 
    return { std::move(p0), std::move(p1) }; 
} 

Dann nutzen Sie einfach, wie Sie ins Auge gefasst:

auto combined = and_p(p0, p1); 

Live Demo

Verwandte Themen