具有多行参数的宏函数? C++中的P> 我需要定义一个宏。 该宏将以代码的“块”作为参数

具有多行参数的宏函数? C++中的P> 我需要定义一个宏。 该宏将以代码的“块”作为参数,c++,macros,C++,Macros,我们可以安全地使用几行代码作为宏函数的参数吗? 我在问自己: 以下代码是否有效,标准定义为有效,如“跨平台”中所述 有没有更好的方法来做同样的事情(我不能在那里使用模板函数,因为我需要上下文) 我们不能使用函子,因为我们需要访问调用的上下文。 我们不能使用lambda(snif),因为我们使用的是一个旧的编译器,它不提供lambda(而且我们不能更改它)。我认为您需要使用额外的括号,使表达式看起来像一个不会被预处理器分解的参数,也就是说,像这样做: #define MY_MACRO( (exp

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

我在问自己:

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

  • 我们不能使用函子,因为我们需要访问调用的上下文。
    我们不能使用lambda(snif),因为我们使用的是一个旧的编译器,它不提供lambda(而且我们不能更改它)。

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

    #define MY_MACRO( (expr) ) DOSOMETHING( (expr) ); DOANOTHERTHING( (expr) ); // etc...
    
    int my_function() {
        MY_MACRO( 
            (int k = AFunction();
            k++;
            AnotherFunction( k );)
        ); 
    }
    

    虽然我还没有尝试过。

    在C++中,你应该使用函子!!p>
    struct忍者
    {
    void运算符()()常量
    {
    int k=a函数();
    k++;
    另一个函数(k);
    }
    };
    模板
    void do_something(函子const&f)
    {
    f();
    }
    模板
    void do_otherthing(函子const&f)
    {
    f();
    }
    int my_函数()
    {
    忍者富;
    做点什么(foo);
    做其他事情(foo);
    }
    
    我看到的主要问题是
    expr
    根本不是一个表达式。它甚至包含一个声明。显然,在
    my_函数
    中定义的两个变量
    k
    会有问题

    如果您可以使用C++0x(例如VS2010、GCC4.6),那么您可以使用lambda来捕获上下文。对于这种简单的情况,您不需要捕获上下文,也不需要模板,您的宏只需要一个
    std::function

    16.3/9:

    在预处理序列中 组成对 函数类似于宏,新行是 被认为是正常的空白 性格

    因此,多行宏调用通常是好的。当然,如果
    DOSOMETHING
    donothing
    没有为范围引入大括号,那么您的特定示例将重新定义
    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));
    }
    
    struct MyFunctor{
    INTO;
    MyFunctor(into):o(o){}
    void运算符()()常量{//实际上可能不是void
    int k=a函数();
    k++;
    另一个函数(k+o);
    }
    };
    模板
    无效点(常数F&F){
    DOSOMETHING(f());
    不做任何事(f());
    }
    int my_函数(){
    int o=随机数();
    DoBothThings(MyFunctor(o));
    }
    
    您还可以通过引用捕获变量(通常使用指针作为数据成员而不是引用,以便可以复制指定函子)


    例如,如果“上下文”是指宏参数和/或宏体可能包含
    break
    goto
    ,因此需要在调用方的词法范围内,则不能使用函子或lambda。可耻;-)

    参数有多行的宏也可以,在多个参数的情况下,它甚至允许在内部使用“逗号”,但我强烈使用“逗号”进行解释,因为如果它对机器来说不是含糊不清的,那么对人类来说肯定是含糊不清的:

    #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;
    }
    
    #包括
    使用名称空间std;
    #定义MACRO2FUN(X,Y)X;Y
    虚函数(inta,intb,intc){
    std::cout使其工作的方法(至少对于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;
         ....
      }
    });
    
    #ifdef调试
    #定义MYDEBUG(X)(X)
    #否则
    #定义MYDEBUG(X)
    #恩迪夫
    MYDEBUG({
    如果(大便发生){
    
    cerr这个宏有什么用?你试过了吗?发生了什么事?我猜你传递的每个表达式“参数”都需要包含在
    ()
    。感谢编辑Paul,我找不到正确的显示方式。@CharlesB:它生成的代码在生成的代码的几个部分插入表达式参数。问题更多的是:我们可以安全地使用几行代码作为宏函数的参数吗?@Paul R:我们正在尝试,但问题更多如果它是由标准定义的(对宏使用多行)如果是跨平台的。@Klaim,如果你解释一下上下文是什么意思,也许会有助于回答问题。例如,你是否需要调用方在
    DOSOMETHING
    donotherthing
    中的所有状态?如果不需要,你不能将你需要的东西封装在一个可以传递给它们的函子中吗?或者在C++0x中,不需要名字吗:
    [](){int k=a函数();++k,另一个函数(k);}
    是的,我们考虑过这一点,但问题是我们需要保留调用的上下文。但是lambda可以解决这个问题,但我们目前无法使用提供lambda功能的编译器TT_utt。我正在更新答案,无论如何,感谢您确认了我的想法。我不太了解这个叫做C++0x的东西…:(Klaim,上下文是什么意思?@ Nim:看看例子,代码需要访问调用函数中的变量。C++ 0x是C++新标准(C++ 2011)的别名。这定义了lambda功能。我也没有尝试过,但我认为逗号是唯一可以分解宏参数的东西。看起来很奇怪,你可以在其中放置分号,而不需要做任何特殊的事情,它仍然是一个恰好包含分号的宏参数。@Steve:啊,好的-这让我很惊讶
    #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;
    }
    
    #ifdef DEBUG
    #define MYDEBUG(X) (X)
    #else
    #define MYDEBUG(X)
    #endif
    
    MYDEBUG({
      if (shit_happens) {
         cerr << "help!" << endl;
         ....
      }
    });