作为一个练习,我想检查一下,在一个assert
中,我以前是否看到过某个(布尔)状态。看到它从来没有是可以的,看到它一次是可以的,但是看到它两次应该会引发一个Assert。(确切地说,在看到它一次之后看到 anything 应该会引发一个Assert。)
我尝试过assert(!(seen & (seen |= is_here)));
--然而,它在不同编译器中的表现非常不一致。
- 在https://www.programiz.com/cpp-programming/online-compiler/,它只是工作。
- 在https://replit.com/languages/cpp,它与有用的警告一起工作(
-Wunsequenced
) - 在MSVC上,第三个调用已经失败
#include <iostream>
#include <assert.h>
int main() {
bool seen = false;
bool is_here;
is_here = false;
// these shall pass
assert(!(seen & (seen |= is_here)));
assert(!(seen & (seen |= is_here)));
is_here = true;
// this shall pass, but fails in MSVC
assert(!(seen & (seen |= is_here)));
// after that, this shall pass
assert( (seen & (seen |= is_here)));
is_here = false;
// same as this
assert( (seen & (seen |= is_here)));
std::cout << "Done.";
return 0;
}
我想我碰到了一堵未定义行为的墙,所以我试着重写我的表达式,但没有成功。(我想这可能是一个逻辑问题,而不是编程问题。)我试着用&&
或||
重写,它们有序列点,但由于它们也是短路的,我还没有找到正确的表达式。
1条答案
按热度按时间xdyibdwo1#
通过反复试验,我已经能够得出
assert(seen ? false : true | (seen |= is_here))
,关键是?
引入了一个序列点,将seen
的两个求值分开,此外,true | ...
设置后一个分支的值,而不会短路。