如果您希望规则是
a == b
返回true时,
a != b
返回false,则确实没有理由有两种实现,除非您希望优化掉一个
!
。 (这很少发生变化,并且最好由优化器完成。)
但是,C++通常不假设运算符重载遵守这种规则。
例如,您可能还认为,只需要重载
operator <
,就可以获得
operator >
、operator
<=
、operator
>=
和operator
==
。如果您认为它返回布尔值并且关系应该是部分顺序,则所有这些都可以用
operator <
定义。
但是,在某些情况下,运算符也用于提供更复杂的语法和语义。如果强加了这些“恒等式”,那么某些东西(例如表达式模板)就会变得不可能。
C++不会对您施加任何“恒等式”。您可以随意赋予操作符任何含义,无论是好是坏。
因此,我认为您所听到的可能是一种误解。您拥有这种自由的原因不是为了提供更多的“效率”机会,而是允许您在使用自定义类时给运算符赋予您想要的含义。
为了完整起见,这里是一个示例。
namespace expression_builder {
struct arg {
bool operator()(bool input) const {
return input;
}
};
template <typename E>
struct negate {
E e;
bool operator()(bool input) const {
return !e(input);
}
};
template <typename E1, typename E2>
struct equals {
E1 e1;
E2 e2;
bool operator()(bool input) const {
return e1(input) == e2(input);
}
};
template <typename E1, typename E2>
struct not_equals {
E1 e1;
E2 e2;
bool operator()(bool input) const {
return e1(input) != e2(input);
}
};
template <typename T>
auto operator!(T t) -> negate<T> {
return {t};
}
template <typename T1, T2>
auto operator==(T1 t1, T2 t2) -> equals<T1, T2> {
return {t1, t2};
}
template <typename T1, T2>
auto operator!=(T1 t1, T2 t2) -> not_equals<T1, T2> {
return {t1, t2};
}
}
int main() {
using expression_builder::arg;
auto my_functor = (arg == (arg != (!arg)));
bool test1 = my_functor(true);
bool test2 = my_functor(false);
}
在这段代码中,使用运算符重载允许您构造函数对象以实现简单的布尔函数。函数构建过程完全发生在编译时,因此生成的代码非常高效。人们在更复杂的示例中使用它来在C++中非常有效地执行某些类型的函数式编程。这里非常关键的是operator ==
与operator !=
有非常不同的实现。