从C++17开始,过载的逻辑运算符&&和||是否会短路?

16
我在http://en.cppreference.com/w/cpp/language/operators中读到:
引用: 布尔逻辑运算符,运算符&&和运算符|| 与内置版本不同,重载版本不会在右操作数之前对左操作数进行排序,并且(直到C++17)无法实现短路评估。
(我强调)。
找不到任何支持运算符&&和运算符||的C++17短路的资源或代码示例。 这与C++17参数包折叠表达式有关吗?尝试过一些操作,但无法使用C++17折叠表达式为重载的运算符&&和||创建短路行为。
代码:
class A {
    bool val;
public:
    A(bool b) : val(b) { cout << "A born as " << boolalpha << val << endl;}
    template<typename ...Args>
    bool operator&&(Args&&... args) {
        return (val && ... && args.val);
    }    
};

int main() {
    cout << boolalpha;
    cout << ( A{false} && A{true} ) << endl;
    cout << ( A{true} && A{false} ) << endl;
    cout << ( A{false} && A{false} ) << endl;
}

输出:

A born as true
A born as false
false
A born as false
A born as true
false
A born as false
A born as false
false

http://coliru.stacked-crooked.com/a/f0b5325899c2fe6b

注意:在当前使用C++17标志编译的gcc版本中,从左到右的顺序也没有发生。

无法创建短路行为。这是什么错误?或者没有错误,只是有副作用表现出来给下游操作符?或者你是否逐步执行代码并进入其他操作符? - wally
1
@Mus 这个问题是关于标准定义的行为,而不是关于代码无法工作的问题。 - interjay
7
这个 (until c++17) 标记适用于“不要将左操作数的顺序排在右操作数之前”,在C++17中,对重载运算符函数的调用遵循与相应内置运算符相同的顺序。据我所知,仍然无法创建短路行为。 - cpplearner
无论如何,operator&&()只能接受一个参数,所以将其写成可变模板有点具有误导性。 - Barry
@Barry:说得好。当然,这也可以通过常规运算符重载进行测试,结果相同——当前的gcc版本仍未实现从左到右的顺序:http://coliru.stacked-crooked.com/a/754a27e8541ad075 - Amir Kirsh
显示剩余2条评论
1个回答

14

这个语句并非关于短路求值,而是关于操作数计算的顺序。

在C++17之前,对于重载的&&和||运算符的操作数求值顺序由编译器定义。C++17明确定义了&&和||的从左到右的显式求值顺序,无论它们是否被重载。

短路求值仍然只适用于内置运算符。

请注意,在您引用的实际页面上,突出显示的部分是针对特定版本的应用。那部分是关于求值顺序的,而不是关于短路求值的部分。


4
这个“until c++17”标签的位置不太恰当。我已经编辑了页面以使语法更清晰。 - user2357112
4
个人而言,只要你知道所有特定版本的标签仅适用于包含它们的框中的文本,那就没问题。 - Nicol Bolas
当然,并不是每个人都知道这一点,而英语语法与版本框之间的不匹配仍然可能会使了解版本框工作原理的人感到困惑。 - user2357112
@user2357112:这个例子(使用C++17标志编译)不是展示了先评估右操作数吗?这是否违反了C++17的顺序注意事项? - Amir Kirsh
1
@AmirKirsh:可能只是还没有实现。 - user2357112

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