C++的逻辑运算符&&和||的短路评估

3

用户在C++中超载逻辑运算符(&&, ||)的行为类似于常规函数。也就是说,在进入函数之前,bool operator&&(const T &a, const T2 &b);中的两个参数都会被评估,因为在C++中进入函数是一个序列点[1]。到此为止一切都很好。

现在,“内置运算符&&和||进行短路计算”[2][3],左右两侧之间有一个序列点。引用的参考文献并不清楚“内置”是什么,只知道它们需要使用bool操作数,或者使用“上下文转换为bool”进行转换。它还提到,只有“两个标准库类重载这些运算符[因为]短路属性(...)不适用于重载,并且具有布尔语义的类型很少。”[2]

具有布尔语义的类型?“内置运算符”究竟是如何工作的?定义具有短路计算的逻辑运算符是否根本不可能?

[1] https://en.wikipedia.org/wiki/Sequence_point

[2] http://en.cppreference.com/w/cpp/language/operator_logical逻辑运算符

[3] https://en.wikipedia.org/wiki/Short-circuit_evaluation短路求值


4
“仅使用短路评估无法定义逻辑运算符吗?”是的,它“简单地不可能”。您的运算符函数需要完全评估两个参数,这意味着编译器不能对其进行任何短路处理。如果您想要自定义类型的短路评估,则需要实现转换运算符到“bool”,而不是逻辑运算符。 - Some programmer dude
1
我的理解是,“builtin”指的是“这是一种内置的语言特性”,而不是“这是标准库的一部分”。除非你使用自己的编译器和非标准扩展,否则你无法创建自己的内置运算符。 - Chris Beck
可能是[是否有任何理由重载的&&和||不进行短路?]的重复内容(https://dev59.com/Y18e5IYBdhLWcg3wRItQ)。 - quamrana
@JoachimPileborg 我认为短路可以在用户定义的逻辑操作中实现,但这并不容易。 - Slava
2个回答

5
你可以想象一下,短路运算符 && 的作用如下:
bool b = expr1 && expr2;

首先,它会将 expr1expr2 存储在lambda中:
bool b = and_helper( [&]{return expr1;}, [&]{return expr2;} );

并将它们转发到一个帮助程序中,其中and_helper略微简化如下:

template<class Lhs, class Rhs>
bool and_helper( Lhs&& lhs, Rhs&& rhs ) {
  if (lhs()) return rhs();
  return false;
}

这个语法具有类似的短路行为。

为了让用户重载的 && 表现出这种行为,我们需要自动将参数转换为 lambda 并将其传递到用户编写的 operator&& 中。

因此,唯一的障碍是语法问题。通过对你的类型进行相对机械的转换,你可以获得相同的行为,而不需要使用魔法来实现。

即使在 lambda 函数不存在时,当编译器遇到该结构时,它也会执行大致等效的操作。


0

这意味着短路不适用于用户定义的运算符。

这是因为,正如您所说,它们的行为类似于函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接