Frage

I Situationen häufig auftreten, vor allem mit in C ++ Sortierung, wo ich eine Reihe von Feldern, um am Vergleich eine größere Struktur zu vergleichen. Ein vereinfachtes Beispiel:

struct Car{
    Manufacturer make;
    ModelName model;
    Year year;
};

bool carLessThanComparator( const Car & car1, const Car & car2 ){
    if( car1.make < car2.make ){
        return true;
    }else if( car1.make == car2.make ){
        if( car1.model < car2.model ){
            return true;
        }else if( car1.model == car2.model ){
            if( car1.year < car2.year ){
                return true;
            }
        }
    }

    return false;
}

Mein instinktiver Ansatz scheint umständlich, vor allem für mehr als 3 Felder. Wie würden Sie diese Reihe von Vergleichen in C ++ strukturieren? Haben andere Sprachen bieten eine prägnante oder elegante Syntax?

War es hilfreich?

Lösung

Nun, wenn Ihre Funktion eine Rückkehr in der trifft, wenn Klausel, gibt es keine Notwendigkeit für einen expliziten sonst , da es schon gebürgt haben würde aus. Das kann auf dem „indent Tal“ speichern:

bool carLessThanComparator( const Car & car1, const Car & car2 ) {
    if( car1.make < car2.make )
        return true;

    if ( car1.make != car2.make )
        return false;

    if( car1.model < car2.model )
        return true;

    if( car1.model != car2.model )
        return false;

    if( car1.year < car2.year )
        return true;

    return false;
}

Ich mag MarkusQ des LISPish Kurzschließen Ansatz als auch.

Andere Tipps

Wenn dies geschieht viel Sie eine Vorlage wie diese in einen gemeinsamen Header setzen könnte:

template<typename T, typename A1, typename A2, typename A3>
bool
do_less_than(
        const typename T& t1,
        const typename T& t2,
        const typename A1 typename T::* a1,
        const typename A2 typename T::* a2,
        const typename A3 typename T::* a3)
{
    if ((t1.*a1) < (t2.*a1)) return true;
    if ((t1.*a1) != (t2.*a1)) return false;
    if ((t1.*a2) < (t2.*a2)) return true;
    if ((t1.*a2) != (t2.*a2)) return false;
    return (t1.*a3) < (t2.*a3);
}

In anderen Vorlagen für unterschiedliche Anzahl von Argumenten, wie erforderlich. Für jede kleiner als Funktion können Sie dann so etwas tun:

bool carLessThanComparator(const Car& car1, const Car& car2)
{
    return do_less_than(car1, car2, &Car::make, &Car::model, &Car::year);
}

Persönlich würde ich vorschlagen, nicht die Verwendung von = oder == Operatoren wie wir scheinen hier zu empfehlen - dies erfordert die Argumente / Mitglieder beide weniger hat dann und gleich Betreiber nur einen kleinen dann überprüfen auf einer Klasse zu tun, die sie enthält, -. nur mit dem weniger als Operator ist genug und werden Sie Redundanz und mögliche Mängel in der Zukunft speichern

Ich schlage vor, Sie schreiben:

bool operator<(const Car &car1, const Car &car2) 
{
    if(car1.make < car2.make)
        return true;
    if(car2.make < car1.make)
        return false;

    if(car1.model < car2.model)
        return true;
    if(car2.model < car1.model)
        return false;

    return car1.year < car2.year;
}

Ich weiß, es ist eine alte Frage, aber für zukünftige Besucher: die moderne C ++ 11-Lösung zu verwenden ist std :: tie

struct Car{
    Manufacturer make;
    ModelName model;
    Year year;
};

bool operator<(Car const& lhs, Car const& rhs)
{
    return std::tie(lhs.make, lhs.model, lhs.year) < std::tie(rhs.make, rhs.model, rhs.year);
}

std::tie wandelt das struct in eine std::tuple so dass die oben genannten Vergleichsoperator Delegierten std::tuple::operator<. Dies wiederum hat eine lexikographische vergleichen in Bezug auf die Reihenfolge, in der die Mitglieder in std::tie vermarshallten werden.

Der lexikographische Vergleich kurzgeschlossen wird in der gleichen Weise wie bei den anderen Lösungen auf diese Frage. Aber es ist noch genug prägnant im Fluge in einem C ++ Lambda-Ausdruck zu definieren. Für die Klassen mit privaten Datenelementen, ist es am besten in der Klasse als friend Funktion definiert ist.

bool carLessThanComparator( const Car & car1, const Car & car2 ){
    return (
      ( car1.make  < car2.make  ) or (( car1.make  == car2.make  ) and
      ( car1.model < car2.model ) or (( car1.model == car2.model ) and
      ( car1.year  < car2.year  ) 
      )));

- MarkusQ

Persönlich würde ich überschreiben die ==, <,> und alle anderen Betreiber benötigt. Das würde den Code, nicht im Vergleich aufzuräumen, aber wenn man den Vergleich vornehmen müssen. Für den Ist-Vergleich selbst, würde ich es in ähnlicher Weise schreiben, was das Crashworks.

bool operator<(const Car &car1, const Car &car2) {
    if(car1.make < car2.make)
        return true;
    if(car1.make != car2.make)
        return false;
    if(car1.model < car2.model)
        return true;
    if(car1.model != car2.model)
        return false;
    return car1.year < car2.year;
}

Ich war das gleiche wie das OP fragen, und über diese Frage gestolpert. Nachdem die Antworten zu lesen ich von Janm und RnR inspiriert wurde, um eine lexicographicalMemberCompare Template-Funktion zu schreiben, die nur nur operator< auf den verglichenen Mitgliedern verwendet. Es nutzt auch boost :: tuple so dass Sie so viele angeben Mitglieder, wie Sie wollen. Hier ist sie:

#include <iostream>
#include <string>
#include <boost/tuple/tuple.hpp>

template <class T, class Cons>
struct LessThan
{
    static bool compare(const T& lhs, const T& rhs, const Cons& cons)
    {
        typedef LessThan<T, typename Cons::tail_type> NextLessThan;
        typename Cons::head_type memberPtr = cons.get_head();
        return lhs.*memberPtr < rhs.*memberPtr ?
            true :
            (rhs.*memberPtr < lhs.*memberPtr  ?
                false :
                NextLessThan::compare(lhs, rhs, cons.get_tail()));
    }
};

template <class T>
struct LessThan<T, class boost::tuples::null_type>
{
    static bool compare(const T& lhs, const T& rhs,
                        const boost::tuples::null_type& cons)
    {
        return false;
    }
};

template <class T, class Tuple>
bool lexicographicalMemberCompare(const T& lhs, const T& rhs,
                                  const Tuple& tuple)
{
    return LessThan<T, typename Tuple::inherited>::compare(lhs, rhs, tuple);
}

struct Car
{
    std::string make;
    std::string model;
    int year;
};

bool carLessThanCompare(const Car& lhs, const Car& rhs)
{
    return lexicographicalMemberCompare(lhs, rhs,
        boost::tuples::make_tuple(&Car::make, &Car::model, &Car::year));
}

int main()
{
    Car car1 = {"Ford", "F150", 2009};
    Car car2 = {"Ford", "Escort", 2009};
    std::cout << carLessThanCompare(car1, car2) << std::endl;
    std::cout << carLessThanCompare(car2, car1) << std::endl;
    return 0;
}

Hope dies ist nützlich, um jemanden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top