我是否必须提供两个不同版本的运算符==
重载,以便无论LHS和LHS如何都可以运行。表达式的RHS变体。例如
Class A {
...
bool operator==(int const& L, A const& R);
bool operator==(A const& L, int const& R);
...
};
用于 -
A a;
int x = 8;
if( a == 5 || x == a){
...
}
为什么需要这样做?不是L == R
== R == L
?
答案 0 :(得分:9)
C ++没有将任何运算符定义为可交换或对称。因此,它无法自动翻译:
if( x == a){
到
if( a == x){
反之亦然。
如果您希望编译器能够正确处理
if( x == a){
您必须将第一个对象的类型operator==
重载为int
或int const&
。
答案 1 :(得分:2)
如果存在从int
到A
的隐式转换,则可以免费获得对称。
class A
{
int i_;
public:
constexpr A(int i) noexcept : i_{i} {}
friend constexpr bool operator==(A const& L, A const& R) noexcept
{return L.i_ == R.i_;}
};
int
main()
{
constexpr A a1{1};
static_assert(a1 == 1, "");
static_assert(1 == a1, "");
}
如果没有,或者您不想在比较时支付隐式转化费用,那么您必须在需要时手动提供。
这是一种自洽的语言设计。如果您不希望从int
到A
进行隐式转换(反之亦然),那么您可能不希望能够隐式转换暗示A
和int
可以相等。但是你可以通过编写自己的异构比较来选择加入这样的设计。
答案 2 :(得分:1)
有一种方法可以做到这一点,而不必每次都写==
。
namespace bob {
struct equality_support {
template<class T, class U>
using supported =
std::integral_constant< bool,
std::is_base_of< equality_support, std::decay_t<T> >{}
&& decltype( (void(std::declval<T>().equals( std::declval<U>() ) ), true) ){true}
>;
template<class T, class U,
class=std::enable_if_t< supported<T const&, U const&>{} >
>
friend bool operator==( T const& t, U const& u ) {
return t.equals(u);
}
template<class T, class U,
class=std::enable_if_t<
!supported<T const&, U const&>{}
&& supported<U const&, T const&>{}
>,
class=void
>
friend bool operator==( T const& t, U const& u ) {
return u.equals(t);
}
template<class T, class U>
friend auto operator!=( T const& t, U const& u )
-> decltype( !(t==u) )
{ return !(t==u); }
};
}
现在,如果我写的那么正确,则从equality_support
派生,然后覆盖bool equals( int ) const
,它将同时发挥作用。
struct A:
bob::equality_support
{
bool equals( int x ) const { return x==42; }
};
测试代码:
int main() {
A a;
std::cout << (a==7) << (a!=7) << (a==42) << (a!=42) << '\n';
std::cout << (a==0.0) << (a=='a') << '\n';
// std::cout << (a == "hello") << "\n"; // does not compile
}
我会选择比bob
更好的命名空间名称。
如果您想支持A==A
,可以执行bool equals( A const& ) const
或转换为int
。
这种技术的运行时间成本接近于零,假设您的编译器进行适度优化和内联。
我所做的是利用参数依赖查找和SFINAE来允许继承equality_support
来编写operator==
和operator!=
,最终调度到(非虚拟){{1}继承自equals
。
它以对称的方式执行此操作,除非equality_support
的两边都有==
,在这种情况下更喜欢调用equality_support
。因此,如果lhs.equals(rhs)
方法是不对称的,那么在这种情况下您将得到不对称的结果。
.equals
会自动写入以反转!=
。
我写的示例==
始终比较等于struct A
;这大多是个玩笑。它可以在42
的主体中做任何想做的事。
我写的SFINAE必须重写才能在MSVC 2015中可靠地工作。它名义上只是一个C ++ 11编译器;它在SFINAE地区的实施仍然存在很大差距。