具有多行参数的宏功能?

问题描述 投票:12回答:6

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

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

我问自己是否:

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

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

c++ macros
6个回答
8
投票

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,因此需要在调用者的词法范围内,然后你不能使用functor或lambda 。耻辱 ;-)


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

1
投票

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

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

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

虽然我还没有尝试过。


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

0
投票

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

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


0
投票

参数的多行宏也可以在多个参数的情况下使用,它甚至允许使用“逗号”,但我强烈建议使用“逗号”,因为如果它不是机器的模糊,它肯定是人类的模糊:

#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;
}
© www.soinside.com 2019 - 2024. All rights reserved.