Подтвердить что ты не робот

Макрофункция с несколькими строками для параметра?

В С++, Мне нужно определить макрос. Этот макрос будет принимать в качестве параметра "блок" кода.

Можно ли безопасно использовать несколько строк кода в качестве параметра макрофункции?

Я спрашивал себя:

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

#define MY_MACRO( expr ) DOSOMETHING( (expr) ); DOANOTHERTHING( (expr) ); // etc...

int my_function() {
    int o = RandomNumber();
    MY_MACRO( 
        int k = AFunction();
        k++;
        AnotherFunction( k + o ); // here I need to keep the context of the call
    ); 
}

Мы не можем использовать функторы, потому что нам нужно иметь доступ к контексту вызова. Мы не можем использовать lambda (snif), потому что мы используем старый компилятор, который его не предоставляет (и мы не можем его изменить).

4b9b3361

Ответ 1

16,3/9:

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

Таким образом, многострочный вызов макросов в целом прекрасен. Конечно, если DOSOMETHING и DOANOTHERTHING не вводят скобки для области видимости, то ваш конкретный пример переопределит k.

Edit:

Мы не можем использовать функторы, потому что нам нужно иметь доступ к контексту вызов. Мы не можем использовать лямбда (snif), потому что мы используем старый компилятор

Обычным способом является захват любых переменных, которые вам нужны в функторе, точно так же, как лямбда. Единственное, что может сделать лямбда, что функтор не может "захватить все", не вводя его, но тот, кто пишет лямбду, может видеть, какие переменные они используют, чтобы просто удобство, они могли набирать их все, если бы они должен был. В вашем примере:

struct MyFunctor {
    int o;
    MyFunctor(int o) : o(o) {}
    void operator()() const {  // probably not void in practice
        int k = AFunction();
        k++;
        AnotherFunction( k + o );
    }
};

template<typename F>
void DoThings(const F &f) {
    DOSOMETHING(f());
    DOANOTHERTHING(f());
}

int my_function() {
    int o = RandomNumber();
    DoBothThings(MyFunctor(o));
}

Вы также можете захватывать переменные по ссылке (обычно используя указатель как элемент данных, а не ссылку, так что функтор может быть назначен для копирования).

Если в контексте "контекст" вы подразумеваете, например, что аргумент макроса и/или тело макроса могут содержать break или goto и, следовательно, должны находиться внутри лексической области вызывающего, тогда вы можете " t используйте функтор или лямбду. Для стыда; -)

Ответ 2

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

#define MY_MACRO( (expr) ) DOSOMETHING( (expr) ); DOANOTHERTHING( (expr) ); // etc...

int my_function() {
    MY_MACRO( 
        (int k = AFunction();
        k++;
        AnotherFunction( k );)
    ); 
}

хотя я на самом деле не пробовал его.

Ответ 3

В С++ вы должны использовать функтор!;)

struct ninja
{
  void operator()() const
  {
    int k = AFunction();
    k++;
    AnotherFunction( k );    
  }
};

template <typename Functor>
void do_something(Functor const& f)
{
  f();
}

template <typename Functor>
void do_otherthing(Functor const& f)
{
  f();
}

int my_function()
{
  ninja foo;
  do_something(foo);
  do_otherthing(foo);
}

<tongue firmly in cheek!/>

Ответ 4

способ заставить его работать (по крайней мере, для gcc версии 4.8.1 (Ubuntu/Linaro 4.8.1-10ubuntu9)) используется использовать фигурные скобки {}, охватывающие ваши фактические для макроса.

Полезный пример:

#ifdef DEBUG
#define MYDEBUG(X) (X)
#else
#define MYDEBUG(X)
#endif

MYDEBUG({
  if (shit_happens) {
     cerr << "help!" << endl;
     ....
  }
});

Ответ 5

Основная проблема, которую я вижу, заключается в том, что expr не является выражением вообще. Он даже содержит декларацию. Очевидно, что у вас будет проблема с двумя переменными k, определенными в my_function.

Если вы можете использовать С++ 0x (например, VS2010, GCC4.6), вы можете использовать lambda для захвата контекста. Не то, чтобы вам нужно было захватить контекст для такого простого случая, и вам не нужны шаблоны, вашему макросу просто нужен std::function<void(void)>.

Ответ 6

Макрос с несколькими строками для параметра отлично подходит и в случае нескольких аргументов, он даже позволяет "запятые" внутри, но я сильно отказываюсь использовать "запятые", потому что если это не ambiguos для машины, то это, безусловно,

#include <iostream>
using namespace std;

#define MACRO2FUN( X, Y) x; y;
void function(int a, int b, int c){
    std::cout<<a<<" "<<b<<" "<<c<<std::endl;
}

int main() {
    MACRO2FUN(
      function(3,4,5), 
      function(6,7,8)
      )
      return 0;
}