C++关系运算符生成器

C++ relational operators generator

本文关键字:运算符 关系 C++      更新时间:2023-10-16

一旦定义了<运算符,就可以估计其他关系运算符的行为。我正在尝试为我的类实现一种方法。

我想要的是只定义<和其他要隐式默认的运算符。到目前为止,我得到的是这个设计,我将在下面详细介绍:

template<typename T>
struct relational
{
    friend bool operator> (T const &lhs, T const &rhs) { return rhs < lhs; }
    friend bool operator==(T const &lhs, T const &rhs) { return !(lhs < rhs || lhs > rhs); }
    friend bool operator!=(T const &lhs, T const &rhs) { return !(rhs == lhs); }
    friend bool operator<=(T const &lhs, T const &rhs) { return !(rhs < lhs); }
    friend bool operator>=(T const &lhs, T const &rhs) { return !(lhs < rhs); }
};

因此,对于实现<运算符的类,只需从relational继承即可默认其余运算符。

struct foo : relational<foo>
{ 
    // implement < operator here
};
  1. 有什么替代方案,更好的设计吗
  2. 这个代码里有定时炸弹吗?我假设,如果用户想为其中一个运算符定义一个自定义实现,重载解决方案将启动并选择非模板(用户定义的(实现。如果不是这样的话(或者我对从relational继承的类模板有问题(,我应该这样实现relational中的运算符吗?

    // inside the relational struct
    friend bool operator>(relational const &lhs, relational const &rhs)
    { // functions that involve implicit conversion are less favourable in overload resolution
            return (T const&)rhs < (T const&)lhs; 
    }
    

感谢您的建议,这里有一个代码工作

的演示

我通常会用从Robert Martin那里学到的技巧来做这件事。我有一个模板类:

template <typename T>
class ComparisonOperators
{
protected:
    ~ComparisonOperators() {}
public:
    friend bool operator==( T const& lhs, T const& rhs )
    {
        return lhs.compare( rhs ) == 0;
    }
    friend bool operator!=( T const& lhs, T const& rhs )
    {
        return lhs.compare( rhs ) != 0;
    }
    friend bool operator<( T const& lhs, T const& rhs )
    {
        return lhs.compare( rhs ) < 0;
    }
    friend bool operator<=( T const& lhs, T const& rhs )
    {
        return lhs.compare( rhs ) <= 0;
    }
    friend bool operator>( T const& lhs, T const& rhs )
    {
        return lhs.compare( rhs ) > 0;
    }
    friend bool operator>=( T const& lhs, T const& rhs )
    {
        return lhs.compare( rhs ) >= 0;
    }
};

需要运算符的类由此派生:

class Toto : public ComparisonOperators<Toto>
{
    // ...
public:
    //      returns value < 0, == 0 or >0, according to
    //      whether this is <, == or > other.
    int compare( Toto const& other ) const;
};

(我的实现实际上有点复杂,因为使用一些简单的元编程来调用isEqual,而不是compare,如果该函数存在的话。(

编辑:

重读你的问题:这基本上就是你在做的事情,这几乎是这类事情的标准习语。我更喜欢使用像compare这样的命名函数,但这只是我个人的偏好。然而,处理isEqual的元编程技巧值得一试:这意味着你可以对只支持相等的类型使用同一个类;当编译器试图实例化operator<=时,你会遇到一个错误,但除非有人使用它,否则编译器不会尝试实例化它。通常情况下,isEqual的实现效率比compare高得多。

编辑2:

值得一提的是:我系统地做这件事。我也有CCD_ 14(例如根据CCD_,MixedTypeArithmeticOperators(与上面类似,但有两个类型,T1(它是基类(和T2;它提供了运算符的所有组合(。和STLIteratorOperators,实现STL迭代器基于更合理、更容易实现(基本上,使用isEqual实现GoF迭代器函数(。它们节省了很多样板。

编辑3:

最后:我只是查看了工具包中的实际代码。有条件地支持isEqual甚至比我记得:上面的模板类有一个公共成员:

bool isEqual( T const& other ) const
{
    return static_cast< T const* >( this )->compare( other ) == 0;
}

operator==operator!=只是使用了isEqual,没有涉及模板元编程。如果派生类定义了一个isEqual,它隐藏了这个CCD_26并被使用。如果不,这个习惯了。

朋友不是继承的,所以这个想法行不通。然而,您可以巧妙地使用宏,例如:

#define GEN(X) 
    friend bool operator> (T const &lhs, T const &rhs) { return rhs < lhs; } 
    friend bool operator==(T const &lhs, T const &rhs) { return !(lhs < rhs || lhs > rhs); } 
    friend bool operator!=(T const &lhs, T const &rhs) { return !(rhs == lhs); } 
    friend bool operator<=(T const &lhs, T const &rhs) { return !(rhs < lhs); } 
    friend bool operator>=(T const &lhs, T const &rhs) { return !(lhs < rhs); }

您可以使用作为:

class Foo
{
...
GEN(foo)
};