问题描述
定义<
运算符后,您可以估计其余关系运算符的行为。我试图实现一个方法来做我的课。
Once you define the <
operator, you can have an estimation of how the rest of relational operators behave. I'm trying to implement a way to do that for my classes.
我想要的只是定义<
,其余的操作符默认默认。我现在到目前为止是这个设计,我将进一步详细说明:
What I want is to define only the <
and the rest of the operators to be defaulted implicitly. What I've got so far is this design, which I'll elaborate on further down:
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); }
};
所以对于实现<
运算符,它只是从关系
继承,以使其余运算符默认。
So for a class that implements the <
operator it would just take inheriting from relational
to have the rest of the operators defaulted.
struct foo : relational<foo>
{
// implement < operator here
};
- 是否有其他选择,更好的设计?
-
此代码中是否有计时炸弹?我假设如果用户想要为其中一个操作符定义一个自定义实现,重载分辨率将踢并选择非模板(用户定义)实现。如果不是这样(或者我会有类模板继承自
关系
的问题)我应该实现关系
like this?
- Are there any alternatives, better designs ?
Is there a time bomb in this code? I'm assuming that if a user wants to define a custom implementation for one of the operators, the overload resolution would kick and select the non template (user defined) implementation. If that's not the case (or I would have problem with class templates inheriting from
relational
) should I implement the operators inrelational
like this ?
// 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;
}
感谢您的意见,这里是一个
Thanks for your advices, here's a demo of the code working
推荐答案
我通常使用我从罗伯特·马丁学到的一个伎俩。
我有一个模板类:
I usually use a trick I learned from Robert Martin to do this.I have a template class:
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;
}
};
需要运算符的类派生自:
The class which needs the operators derives from this:
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;
};
(我的实现实际上有点复杂,因为
使用一些简单的meta-编程调用 isEqual
,而不是
比较
,如果该函数存在。)
(My implementation is actually a bit more complicated, since ituses some simple meta-programming to call isEqual
, rather thancompare
, if that function exists.)
编辑:
并重读你的问题:这基本上是你在做什么,这几乎是这个标准的习语那类的东西。我喜欢使用命名的函数,如 compare
,但这只是一个个人偏好。但是,处理 isEqual
的元编程技巧是值得讨论的:它意味着你可以为只支持等式的类型使用相同的类;你会得到一个错误,当编译器试图实例化。 operator< =
,但编译器不会尝试实例化它,除非有人使用它。通常情况下, isEqual
可以比比较
更有效地实现。
And rereading your question: this is basically what you're doing, and it's pretty much the standard idiom for this sort of thing. I prefer using named functions like compare
, but that is just a personal preference. The meta-programming trick to handle isEqual
, however, is worth the bother: it means that you can use the same class for types which only support equality; you'll get an error when the compiler tries to instantiate e.g. operator<=
, but the compiler won't try to instantiate it unless someone uses it. And it's often the case the isEqual
can be implemented a lot more efficiently than compare
.
编辑2:
值得:我这样做是系统的。我还有
ArithmeticOperators
(定义例如 +
,以 + = / code>),
MixedTypeArithmeticOperators
(像上面,但是有两个
类型, T1
,它是一个基类, T2
; it
提供了所有的运算符组合)。和
STLIteratorOperators
,它实现了STL迭代器
接口基于更合理和更容易
实现(基本上,GoF迭代器 isEqual
函数)。他们节省了很多样板。
For what it's worth: I do this systematically. I also have
ArithmeticOperators
(defining e.g. +
in terms of +=
),MixedTypeArithmeticOperators
(like the above, but with twotypes, T1
, for which it is a base class, and T2
; itprovides all of the combination of operators). andSTLIteratorOperators
, which implements the STL iteratorinterface based on something more rational and easier toimplement (basically, the GoF iterator with an isEqual
function). They saves a lot of boilerplate.
编辑3:
最后:在我的工具包。
有条件支持 isEqual
甚至比
更简单我记得:上面的模板类有一个公共成员:
And finally: I just looked at the actual code in my toolkit.Conditionally supporting
isEqual
is even simpler thanI remembered: the template class above has a public member:
bool isEqual( T const& other ) const
{
return static_cast< T const* >( this )->compare( other ) == 0;
}
且
operator ==
和 operator!=
只需使用 isEqual
,不需要
模板元编程。如果派生类
定义了一个 isEqual
,它隐藏了这一个,它被使用。如果
不,这个被使用。
And
operator==
and operator!=
just use isEqual
, notemplate meta-programming involved. If the derived classdefines an isEqual
, it hides this one, and it gets used. Ifnot, this one gets used.
这篇关于C ++关系运算符生成器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!