2009-03-22 7 views
4

Je suis en train de concevoir plusieurs classes qui doivent prendre en charge les opérateurs !=, >, <= et >=. Ces opérateurs seront implémentés en termes d'opérateurs == et <. À ce stade, je dois faire un choix entre l'héritage¹ et forcer mes consommateurs à utiliser std::rel_ops ² "manuellement".Dilemme d'implémentation de l'opérateur relationnel

[1] L'héritage (de mise en œuvre possible):

template<class T> class RelationalOperatorsImpl 
{ 
    protected: 
    RelationalOperatorsImpl() {} 
    ~RelationalOperatorsImpl() {} 

    friend bool operator!=(const T& lhs, const T& rhs) {return !(lhs == rhs);} 
    friend bool operator>(const T& lhs, const T& rhs) {return (rhs < lhs);} 
    friend bool operator<=(const T& lhs, const T& rhs) {return !(rhs < lhs);} 
    friend bool operator>=(const T& lhs, const T& rhs) {return !(lhs < rhs);} 
}; 

template<typename T> class Foo : RelationalOperatorsImpl< Foo<T> > 
{ 
    public: 
    explicit Foo(const T& value) : m_Value(value) {} 

    friend bool operator==(const Foo& lhs, const Foo& rhs) {return (lhs.m_Value == rhs.m_Value);} 
    friend bool operator<(const Foo& lhs, const Foo& rhs) {return (lhs.m_Value < rhs.m_Value);} 

    private: 
    T m_Value; 
}; 

[2] std::rel_ops colle:

template<typename T> class Foo 
{ 
    public: 
    explicit Foo(const T& value) : m_Value(value) {} 

    friend bool operator==(const Foo& lhs, const Foo& rhs) {return (lhs.m_Value == rhs.m_Value);} 
    friend bool operator<(const Foo& lhs, const Foo& rhs) {return (lhs.m_Value < rhs.m_Value);} 

    private: 
    T m_Value; 
}; 

void Consumer() 
{ 
    using namespace std::rel_ops; 

    //Operators !=, >, >=, and <= will be instantiated for Foo<T> (in this case) on demand. 
} 

Je suis fondamentalement en essayant d'éviter la répétition de code. Des pensées quant à la méthode qui "sent" le mieux?

Répondre

5

Avez-vous envisagé d'utiliser boost et que votre classe hérite de boost::less_than_comparable<T> et boost::equality_comparable<T>? C'est comme votre première suggestion, avec quelques avantages et inconvénients. Avantages: évite la duplication de code; Inconvénients: crée une dépendance sur boost. Étant donné que boost est une bibliothèque C++ très courante (si vous ne l'utilisez pas déjà, vous devriez sérieusement envisager de l'utiliser), le facteur de conicité est grisé.

+0

C'est une excellente suggestion. Boost ne cesse jamais de me surprendre. J'aimerais entendre les commentaires des autres avant d'accepter une réponse, cependant. ;) –

1

Je pense que std::rel_ops est assez sympa, mais il y a une chose à considérer en premier: std::rel_ops fournit des opérateurs comme des fonctions de modèle qui acceptent deux paramètres du même type. Comme la plupart des conversions (y compris les promotions arithmétiques et les conversions définies par l'utilisateur) ne sont pas effectuées lors de la déduction des arguments du modèle, cela signifie que vous ne pourrez utiliser aucun de ces opérateurs supplémentaires (par exemple !=) avec de telles conversions.

E.g. si vous avez une classe MyInt qui tente de se comporter comme un entier régulier, vous pourriez avoir des fonctions de conversion écrites/constructeurs ou opérateurs templated afin que vous puissiez faire

MyInt x, y; 

x < 5; 
9 == x; 

Cependant,

x > 5; 
30 <= x; 

ne sera pas travaillez (avec std::rel_ops) car les deux arguments sont de types différents, la déduction d'argument de modèle échouera donc.

Questions connexes