1

I want to achieve something like Boost library does with its macros (e.g. just like BOOST_FOREACH).

This is an example of macro I currently use:

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


std::mutex mutex;

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

I want known how to modify it in such a way, so I can use LOCK_GUARD like below:

LOCK_GUARD(mutex)
{
    // body...
}
Jorengarenar
  • 2,705
  • 5
  • 23
  • 60
aaaa
  • 79
  • 5
  • Does this answer your question? [Is there a way to define variables of two different types in a for loop initializer?](https://stackoverflow.com/questions/866012/is-there-a-way-to-define-variables-of-two-different-types-in-a-for-loop-initiali) – Davis Herring Jul 10 '20 at 21:30
  • 1
    @davis-herring It has nothing to do with this question – Jorengarenar Jul 10 '20 at 21:45
  • @Jorengarenar: Doesn’t it? The title aside, it turns out that what they wanted was to write a macro that accepted a *following* statement, which is exactly the issue here. The question you found is a better match, though. – Davis Herring Jul 10 '20 at 23:13
  • 1
    @DavisHerring My answer to this question doesn't even use a `for` loop. :/ I don't think it's a dupe. (Not even a dupe of what Jorengarenar linked, because that thread is about C.) – HolyBlackCat Jul 10 '20 at 23:18
  • @HolyBlackCat: No one’s insisting that you vote for it or explain why not; inaction here implies disagreement. I do think it’s a duplicate of the other question (and would change my close vote I could): C and C++ do share much of the same preprocessor. – Davis Herring Jul 11 '20 at 00:03

2 Answers2

0

EDIT: Although it's for C, I think the accepted answer to Possible to define a function-like macro with a variable body? can be of use here.


It's possible to create macro in such fashion by utilizing for loop. Example:

#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;
}

Both loops will execute if flag is true. First loop initializes flag to this value. Second loop creates object foo. After expansion the "body" of TEST becomes the body of second loop. After executing the code (everything declared inside body is should be properly destroyed by now), the second loop sets flag to false and therefore ends. First loops also ends and destroys the flag.


The problem is, you want to use it in multithreaded program. This approach will certainly result in data races.

Personally, I wouldn't play around with such macros, but just simply do something in such manner:

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


std::mutex;

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

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

Or else still with macros:

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

std::mutex;

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

    {
        LOCK_GUARD(mutex);
        // body..
    }
}
Jorengarenar
  • 2,705
  • 5
  • 23
  • 60
0

Define the variable in an if condition. Then your code block can be the if body.

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

Note false) {} else instead of true) - it prevents elses in user code from attaching to the macro.

Note that using a loop (that only executes once) in place of if would be problematic, as break and continue would be able to interact with it, which is not good.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
  • I tried that at first,it works inside of function,but it can't be use like this ```auto func = [] LOCK_GUARD(class_member_mutex_) {//....body}``` – aaaa Jul 10 '20 at 21:57
  • @aaaa I doubt there is anything what would work with such bizarre use, because `LOCK_GUARD` isn't a function. – Jorengarenar Jul 10 '20 at 22:03
  • @Jorengarenar i have half idear ,```#define LOCK_GUARD(var) { std::lock_guard ___scope__(var);func() }void func``` follow this way,maybe it can be achieve,right? – aaaa Jul 10 '20 at 22:21
  • @aaaa Uhh, that requirement is not in the question. Can `BOOST_FOREACH` do it? I'm pretty sure that it's either impossible or very hard, and isn't worth it anyway. I suggest settling for `[]{LOCK_GUARD(foo){...}}`. – HolyBlackCat Jul 10 '20 at 23:09
  • 1
    @aaaa Please, don't make it more complicated than it already is – Jorengarenar Jul 10 '20 at 23:09
  • @aaaa I have some ideas how it could be done for captureless lambdas (involving friend-injection, which is a huge overkill for the sole purpose of getting rid of a pair of braces), but I don't think there's a way to make it work for a capturing lambda. – HolyBlackCat Jul 10 '20 at 23:52