编写一次性“如果”的最优雅方式

新手上路,请多包涵

由于 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 的时间和地点吗?我希望不是。

原文由 nada 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 446
2 个回答

使用 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;
    }
};

原文由 Acorn 发布,翻译遵循 CC BY-SA 4.0 许可协议

也许不是最优雅的解决方案,而且您看不到任何实际的 if ,但标准库实际上涵盖了这种情况:参见 std::call_once

 #include <mutex>

std::once_flag flag;

for (int i = 0; i < 10; ++i)
    std::call_once(flag, [](){ std::puts("once\n"); });

这里的优点是这是线程安全的。

原文由 lubgr 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题