C ++ MACRO, который будет выполнять блок кода и определенную команду после этого блока - PullRequest
2 голосов
/ 07 июня 2010
void main()
{
    int xyz = 123; // original value
    { // code block starts
        xyz++;
        if(xyz < 1000)
            xyz = 1;
    } // code block ends
    int original_value = xyz; // should be 123
}

void main()
{
    int xyz = 123; // original value
    MACRO_NAME(xyz = 123) // the macro takes the code code that should be executed at the end of the block.
    { // code block starts
        xyz++;
        if(xyz < 1000)
            xyz = 1;
    } // code block ends << how to make the macro execute the "xyz = 123" statement?
    int original_value = xyz; // should be 123
}

Работает только первый main().
Я думаю, что комментарии объясняют проблему.

Это не обязательно должен быть макрос, но для меня это звучит просто как классический "необходимый макрос" случай.

Кстати, есть макрос / библиотека BOOST_FOREACH, и я думаю, что она делает то же самое, чего я пытаюсь достичь, но мне слишком сложно найти суть того, что мне нужно.
Например, на начальной странице руководства:

#include <string>
#include <iostream>
#include <boost/foreach.hpp>

int main()
{
    std::string hello( "Hello, world!" );

    BOOST_FOREACH( char ch, hello )
    {
        std::cout << ch;
    }

    return 0;
}

Ответы [ 3 ]

8 голосов
/ 07 июня 2010

Самый простой способ сделать это, вероятно, использовать контейнер RAII для сброса значения:

// Assumes T's assignment does not throw
template <typename T> struct ResetValue
{
    ResetValue(T& o, T v) : object_(o), value_(v) { }
    ~ResetValue() { object_ = value_; }

    T& object_;
    T value_;
};

используется как:

{
    ResetValue<int> resetter(xyz, 123);
    // ...
}

Когда блок заканчивается, деструктор будетвызывать, возвращая объект к указанному значению.

Если вы действительно хотите использовать макрос, если это относительно простое выражение, вы можете сделать это, используя forблок:

for (bool b = false; b == false; b = true, (xyz = 123))
{
    // ...
}

, который можно превратить в макрос:

#define DO_AFTER_BLOCK(expr) \
    for (bool DO_AFTER_BLOCK_FLAG = false; \
         DO_AFTER_BLOCK_FLAG == false; \
         DO_AFTER_BLOCK_FLAG = true, (expr))

, используемый как:

DO_AFTER_BLOCK(xyz = 123)
{
    // ...
}

Я не думаю, что макро подходхорошая идея;Вероятно, я бы смутился, если бы увидел это в рабочем исходном коде.

2 голосов
/ 07 июня 2010

Вам абсолютно не нужен макрос - вы могли бы использовать переменные внутренней области видимости:

#include <stdio.h>
int main(void)
{
    int xyz = 123;
    printf("xyz = %d\n", xyz);
    {
        int pqr = xyz;
        int xyz = pqr;
        printf("xyz = %d\n", xyz);
        xyz++;
        if (xyz < 1000)
            xyz = 1;
        printf("xyz = %d\n", xyz);
    }
    printf("xyz = %d\n", xyz);
    return(0);
}

Это приводит к выводу:

xyz = 123
xyz = 123
xyz = 1
xyz = 123

Если вы компилируете с GCC и -Wshadow вы получаете предупреждение;в противном случае он компилируется.Вы не можете написать int xyz = xyz; во внутренний блок надежно;после анализа '=' объявление завершается, и поэтому инициализатором является внутренний 'xyz', а не внешний.Хотя работает два шага.

Основным недостатком этого является то, что он требует модификации в блоке кода.

Если в блоке есть побочные эффекты, такие как операторы печативыше - вы можете вызвать функцию, которая содержит внутренний блок.Если в блоке нет побочных эффектов, зачем вы вообще его выполняете.

#include <stdio.h>
static void inner(int xyz)
{
    printf("xyz = %d\n", xyz);
    xyz++;
    if (xyz < 1000)
        xyz = 1;
    printf("xyz = %d\n", xyz);
}

int main(void)
{
    int xyz = 123;
    printf("xyz = %d\n", xyz);
    inner(xyz);
    printf("xyz = %d\n", xyz);
    return(0);
}
0 голосов
/ 07 июня 2010

Вы не можете заставить макрос выполнять команду после цикла, если вы не поместите цикл в макрос.А серьезно?Лучше было бы просто создать переменную с заданной областью действия.

template<typename T> class CallFunctionOnScopeExit {
    T t;
public:
    CallFunctionOnScopeExit(T tt) : t(tt) {}
    ~CallFunctionOnScopeExit() { t(); }
};

Гарантируется в исключительных случаях и т. Д., В то время как версия макроса определенно не гарантирована.Я бы предпочел использовать этот шаблон для гарантий исключений и потому, что он более гибкий, чем просто копирование int.

...