首页 > 解决方案 > 编写一次性“如果”的最优雅方式

问题描述

由于 C++ 17 可以编写一个if只执行一次的块,如下所示:

#include <iostream>
int main() {
    for (unsigned i = 0; i < 10; ++i) {

        if (static bool do_once = true; do_once) { // Enter only once
            std::cout << "hello one-shot" << std::endl;
            // Possibly much more code
            do_once = false;
        }

    }
}

我知道我可能想多了,还有其他方法可以解决这个问题,但是 - 是否可以像这样写这个,所以do_once = false最后不需要?

if (DO_ONCE) {
    // Do stuff
}

我正在考虑一个do_once()包含 的辅助函数,static bool do_once但是如果我想在不同的地方使用相同的函数怎么办?这可能是一个时间和地点#define吗?我希望不是。

标签: c++if-statementc++17

解决方案


使用std::exchange

if (static bool do_once = true; std::exchange(do_once, false))

您可以缩短反转真值:

if (static bool do_once; !std::exchange(do_once, true))

但是,如果您经常使用它,请不要花哨并创建一个包装器:

struct Once {
    bool b = true;
    explicit operator bool() { return std::exchange(b, false); }
};

并像这样使用它:

if (static Once once; once)

该变量不应该在条件之外被引用,所以这个名字并没有给我们带来太多好处。从给标识符赋予特殊含义的其他语言(如Python_ )中汲取灵感,我们可以这样写:

if (static Once _; _)

进一步改进:利用 BSS 部分(@Deduplicator),避免在我们已经运行时写入内存(@ShadowRanger),如果您要进行多次测试(例如,就像问题中一样),请给出分支预测提示:

// GCC, Clang, icc only; use [[likely]] in C++20 instead
#define likely(x) __builtin_expect(!!(x), 1)

struct Once {
    bool b = false;
    explicit operator bool()
    {
        if (likely(b))
            return false;

        b = true;
        return true;
    }
};

推荐阅读