每个程序员都应该知道:
在某些情况下,为了优化程序,编译器可能会修改(!p && !q)
为(!(p || q))
。
这两个表达式是等效的,并且对第一个或第二个表达式的求值没有区别。
但是在C ++中,可能会重载运算符,而重载的运算符可能并不总是尊重此属性。因此,以这种方式转换代码实际上将修改代码。
当和重载时!
,编译器是否应使用De Morgan定律?||
&&
每个程序员都应该知道:
在某些情况下,为了优化程序,编译器可能会修改(!p && !q)
为(!(p || q))
。
这两个表达式是等效的,并且对第一个或第二个表达式的求值没有区别。
但是在C ++中,可能会重载运算符,而重载的运算符可能并不总是尊重此属性。因此,以这种方式转换代码实际上将修改代码。
当和重载时!
,编译器是否应使用De Morgan定律?||
&&
p
和q
是布尔型原语时,可以确定地应用De Morgan定律,因为这不会改变可观察的行为。当p
并且q
有重载的运算符时,这可能是正确的,也可能不是。C ++标准并没有说明De Morgan的定律。仅由于知道编译器不会改变行为,才“允许”编译器使用它。
if (p || q) { f(); } else { g(); }
能够回答“在什么条件下被g()
调用?” 有人可能会说“ when (p || q)
is false”,但是大多数人都可以应用DeMorgan定理,并且知道“f()
如果p或q均为真,则g()
当p和q均为假时就会被调用”,这就是定律,即使他们不称呼它们按名字。
Answers:
注意:
内置运算符&&和|| 执行短路评估(如果在评估第一个操作数后知道结果,则不要评估第二个操作数),但是重载运算符的行为类似于常规函数调用,并且始终评估两个操作数。
...因为运算符&&和运算符||的短路特性 不适用于重载,并且由于具有布尔语义的类型不常见,因此只有两个标准库类使这些运算符重载...
资料来源:http : //en.cppreference.com/w/cpp/language/operator_ologic (重点是我的)
然后:
如果存在与内置候选运算符功能具有相同名称和参数类型的用户编写的候选,则内置运算符功能将被隐藏,并且不包含在候选功能集中。
来源:n4431 13.6内置运算符[over.built](强调我的)
总结一下:重载运算符的行为类似于常规的用户编写的函数。
不,编译器不会用另一个用户编写的函数来代替用户编写的函数。否则可能会违反“好像”规则。
我认为您已经回答了自己的问题:不,编译器无法执行此操作。不仅运算符可以重载,有些甚至无法定义。例如,您可以拥有operator &&
和operator !
定义,以及operator ||
根本没有定义。
请注意,还有许多其他法律是编译器无法遵循的。例如,它不能改变p||q
到q||p
,以及x+y
到y+x
。
(以上所有内容均适用于重载运算符,因为这是问题的要求。)
不,在这种情况下,转换将无效。改造许可!p && !q
为!(p || q)
是隐含的,由AS-if规则。假设规则允许进行任何粗略地说不能由正确程序观察到的转换。当使用重载运算符并检测到转换时,这自动意味着不再允许转换。
重载的运算符本身只是函数调用的语法糖; 不允许编译器本身对此类调用可能具有或不具有的属性做任何假设。只有当“实算子”时,才能采用利用某些特定算子的属性的优化(例如,De Morgan的布尔算子,和的可交换性,和/乘的分布性,积分除法的转换等)。被使用。
相反,请注意,标准库的某些部分可能会将某些特定的语义与重载的运算符相关联-例如,std::sort
默认情况下,期望operator<
符合元素之间严格的弱顺序的,但这当然在每种算法/的前提条件中都列出了容器。
(顺便说一句,过载,&&
并且||
无论如何都应避免,因为它们在过载时会失去短路特性,因此它们的行为会变得令人惊讶并因此具有潜在的危险)
您正在询问编译器是否可以任意重写您的程序以执行您未编写的程序。
答案是:当然不会!
真的就是这么简单。
x != y
用!(x == y)
。它没有这样的规则,但这并不明显。
DeMorgan的定律适用于这些运算符的语义。重载适用于这些运算符的语法。无法保证重载的运算符会实现DeMorgan律适用的语义。
但是在C ++中,可能会重载运算符,而重载的运算符可能并不总是尊重此属性。
重载的运算符不再是运算符,它是一个函数调用。
class Boolean
{
bool value;
..
Boolean operator||(const Boolean& b)
{
Boolean c;
c.value = this->value || b.value;
return c;
}
Boolean logical_or(const Boolean& b)
{
Boolean c;
c.value = this->value || b.value;
return c;
}
}
所以这行代码
Boolean a (true);
Boolean b (false);
Boolean c = a || b;
等于这个
Boolean c = a.logical_or(b);