具有多行参数的宏功能?

时间:2011-04-06 12:37:24

标签: c++ macros

在C ++中, 我需要定义一个宏。 该宏将参数作为代码的“块”。

我们可以安全地使用几行代码作为宏功能的参数吗?

我问自己是否:

  1. 以下代码是否有效,由标准定义为有效,如“跨平台”?
  2. 有更好的方法来做同样的事情(我不能在那里使用模板函数,因为我需要上下文)。

  3. #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),因为我们使用的是一个不提供它的旧编译器(我们无法更改它)。

6 个答案:

答案 0 :(得分:9)

16.3 / 9:

  

在预处理序列中   令牌组成一个调用   功能一样的宏,新线是   被认为是正常的白色空间   字符。

所以多线宏调用一般都没问题。当然,如果DOSOMETHINGDOANOTHERTHING没有为范围引入大括号,那么您的特定示例将重新定义k

编辑:

  

我们不能使用仿函数,因为我们需要   有权访问上下文   呼叫。我们不能使用lambda(snif),因为我们使用旧的编译器

通常的方法是捕捉算子中需要的任何变量,就像lambda一样。一个lambda可以做的唯一的事情是仿函数不能“捕获所有东西”而不必输入它,但是编写lambda的人可以看到他们使用的变量,所以这只是方便,他们可以输入全部,如果他们必须。在您的示例中:

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

您还可以通过引用捕获变量(通常使用指针作为数据成员而不是引用,以便可以对仿函数进行复制分配)。

如果通过“context”,你的意思是例如宏参数和/或宏体可能包含breakgoto,因此需要在调用者的词法范围内那么你不能使用仿函数或lambda。羞耻; - )

答案 1 :(得分:2)

使它工作的方式(至少对于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;
     ....
  }
});

答案 2 :(得分:1)

我认为你需要使用额外的括号来使你的表达式看起来像一个参数,它不会被预处理器分解,即更像是这样:

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

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

虽然我实际上没有尝试过。

答案 3 :(得分:1)

在C ++中你应该使用仿函数! ;)

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

答案 4 :(得分:0)

我看到的主要问题是expr根本不是表达式。它甚至包含一个声明。显然,k中定义的两个变量my_function会出现问题。

如果你可以使用C ++ 0x(例如VS2010,GCC4.6),那么你可以使用lambda来捕获上下文。并不是说您需要为这样一个简单的案例捕获上下文,也不需要模板,您的宏只需要std::function<void(void)>

答案 5 :(得分:0)

在多个参数的情况下,具有多行参数的宏也可以,它甚至允许使用&#34;逗号&#34;在里面,但我强烈建议使用&#34;逗号&#34;如果它不是机器的模糊,它肯定是对人类的模糊:

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