【问题标题】:How to use the block of code following the macro in the macro?如何在宏中使用宏后面的代码块?
【发布时间】:2020-07-10 20:02:24
【问题描述】:

我想用它的宏实现 Boost 库所做的事情(例如,就像 BOOST_FOREACH)。

这是我目前使用的宏示例:

#define LOCK_GUARD(var, block) { std::lock_guard<std::mutex> ___scope__(var); block }


std::mutex mutex;

LOCK_GUARD(mutex, {
    // body...
});

我想知道如何以这种方式修改它,所以我可以使用LOCK_GUARD,如下所示:

LOCK_GUARD(mutex)
{
    // body...
}

【问题讨论】:

  • @davis-herring 和这个问题无关
  • @Jorengarenar:不是吗?撇开标题不谈,事实证明他们想要的是编写一个接受 following 语句的宏,这正是这里的问题。不过,您找到的问题更匹配。
  • @DavisHerring 我对这个问题的回答甚至没有使用for 循环。 :/我不认为这是一个骗局。 (甚至连 Jorengarenar 链接的内容都没有被欺骗,因为该线程是关于 C 的。)
  • @HolyBlackCat:没有人坚持要你投票或解释为什么不投票;这里的不作为意味着不同意。我确实认为这是另一个问题的重复(并且可能会改变我的近距离投票):C 和 C++ 确实共享许多相同的预处理器。

标签: c++ scope macros brackets


【解决方案1】:

if 条件中定义变量。那么你的代码块可以是if body。

#define LOCK_GUARD(var) \
    if (::std::lock_guard<std::mutex> _lock_guard_(var); false) {} else

注意false) {} else 而不是true) - 它会阻止用户代码中的elses 附加到宏。

请注意,使用循环(只执行一次)代替if 会出现问题,因为breakcontinue 将能够与之交互,这是不好的。

【讨论】:

  • 我一开始试过,它在函数内部工作,但不能像这样使用auto func = [] LOCK_GUARD(class_member_mutex_) {//....body}
  • @aaaa 我怀疑有什么东西可以用于这种奇怪的用途,因为LOCK_GUARD 不是一个函数。
  • @Jorengarenar 我有一半的想法,#define LOCK_GUARD(var) { std::lock_guard&lt;std::mutex&gt; ___scope__(var);func() }void func 按照这种方式,也许可以实现,对吧?
  • @aaaa 呃,这个要求不在问题中。 BOOST_FOREACH可以吗?我很确定这要么是不可能的,要么是非常困难的,而且无论如何都不值得。我建议选择[]{LOCK_GUARD(foo){...}}
  • @aaaa 请不要让它变得比现在更复杂
【解决方案2】:

编辑: 虽然它是针对 C 语言的,但我认为Possible to define a function-like macro with a variable body? 的公认答案可以在这里使用。


可以通过使用for 循环以这种方式创建宏。示例:

#include <iostream>

struct Foo {
    int bar;
    Foo(int bar) : bar(bar) { std::cout << 1 << std::endl; }
    ~Foo() { std::cout << 3 << std::endl; }
};

#define TEST(var) \
    for (bool flag = true; flag; ) \
        for (Foo foo(var); flag; flag = false)

int main()
{
    int x = 2;
    TEST(x) {
        std::cout << foo.bar << std::endl;
    }
    // std::cout << foo.bar << std::endl; // ERROR: ‘foo’ was not declared in this scope
    std::cout << 4 << std::endl;
    return 0;
}

如果flag 为真,则两个循环都将执行。第一个循环将flag 初始化为此值。第二个循环创建对象foo。扩展后TEST 的“主体”成为第二个循环的主体。执行代码后(在 body 中声明的所有内容现在都应该被正确销毁),第二个循环将 flag 设置为 false 并因此结束。第一个循环也结束并销毁flag


问题是,你想在多线程程序中使用它。这种方法肯定会导致数据竞争。

就我个人而言,我不会玩这些宏,而只是简单地以这种方式做一些事情:

using mutex_lock_guard = std::lock_guard<std::mutex>;


std::mutex;

void func(int x)
{
    // init...

    {
        mutex_lock_guard lock(mutex);
        // body..
    }
}

否则仍然使用宏:

#define LOCK_GUARD(var) std::lock_guard<std::mutex> lock(var)

std::mutex;

void func(int x)
{
    // init...

    {
        LOCK_GUARD(mutex);
        // body..
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-17
    相关资源
    最近更新 更多