Как использовать в макросе блок кода, следующий за макросом? - PullRequest
1 голос
/ 10 июля 2020

Я хочу добиться чего-то вроде библиотеки Boost со своими макросами (например, как BOOST_FOREACH).

Это пример макроса, который я сейчас использую:

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


std::mutex mutex;

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

I хотите знать, как изменить его таким образом, поэтому я могу использовать LOCK_GUARD, как показано ниже:

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

Ответы [ 2 ]

0 голосов
/ 11 июля 2020

Определите переменную в условии if. Тогда ваш блок кода может быть телом if.

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

Примечание false) {} else вместо true) - это предотвращает присоединение else s в пользовательском коде к макросу.

Обратите внимание, что использование al oop (которое выполняется только один раз) вместо if будет проблематичным c, так как break и continue смогут взаимодействовать с ним, что нехорошо.

0 голосов
/ 11 июля 2020

РЕДАКТИРОВАТЬ: Хотя это для C, я думаю, что принятый ответ на Можно ли определить функционально-подобный макрос с переменным телом? может быть здесь использован.

Можно создать макрос таким образом, используя for l oop. Пример:

#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 истинно. Сначала l oop инициализирует flag этим значением. Второй l oop создает объект foo. После расширения "тело" TEST становится телом второго l oop. После выполнения кода (все, что объявлено внутри body, к настоящему времени должно быть должным образом уничтожено), второй l oop устанавливает 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..
    }
}
...