【问题标题】:How to pass arbitrary code block to C macro as a param如何将任意代码块作为参数传递给 C 宏
【发布时间】:2013-09-04 08:35:29
【问题描述】:

我想创建一个宏,它将接受任意代码块作为其参数,如

FOR_VECTOR( type, vect, code_block ) \
  for( vector<type>::iterator i=vect.begin(); i!=vect.end(); ++i ) { \
    code_block; \
  }

问题是参数中的代码块,其中可能包含任意数量的,)字符。

有什么好的解决办法吗?

【问题讨论】:

  • 你的意思是除了“不要那样做”吗?你熟悉函数吗?函子?或者在 C++11 中,lamdas ?
  • 他 ^^ 说的。除此之外,将其括起来。预处理器足够聪明,可以识别括号。
  • 好的,我会考虑所有替代方案,但我想要这样一个宏:) 而且我不能用括号括住完整的代码块,只有一个表达式。

标签: c++ macros comma


【解决方案1】:

有许多可能的解决方案。

如果您只需要一个表达式(而不是完整的代码块) - 您可以将其包含在 ()

FOR_VECTOR( int, v, (func(i,1)) )

会起作用 - (func(i,1)) 被视为单个宏参数

另一个部分解决方案是variadic macros,如果你的预处理器支持的话。

你可以定义宏

#define COMMA ,
#define LPAR (
#define RPAR )

并使用它们来形成您的代码块,其中包含真实的 ( ,)

FOR_VECTOR( int, v, func LPAR i COMMA 1 RPAR )

但它的可读性不是很好。

或者您可以在宏替换后注释掉字符串文字的引号:

FOR_VECTOR( type, vect, code_block ) \
  for( vector<type>::iterator i=vect.begin(); i!=vect.end(); ++i ) { \
    /code_block/; \
  }

FOR_VECTOR( int, v, *"*/ func(i,1); proc(i,2); /*"* )

【讨论】:

  • 我为除您之外需要维护该代码的任何人而哭泣。 :)
  • 这是否有效?我尝试过的所有编译器都会出错。无论如何,这不应该产生/* 令牌。预处理器在替换宏参数时不会粘贴标记。你必须写/##code_block,但这不会产生一个有效的令牌:error: pasting "/" and "*" does not give a valid preprocessing token
  • @Hedede 该示例取自实际有效的 C++ 代码,在 2007 年附近编译。就任何合理的代码样式约定而言,这个技巧看起来都非常“可疑”,并且在将 lambda 函数引入 C++ 之后,我认为这样做绝对没有意义。我将更新答案以讲述它。
【解决方案2】:

正如@mas.morozov 提到的,您可以使用可变参数宏:

#include <iostream>
#include <vector>

#define FOR_VECTOR( type, vect, ... ) \
  for( std::vector<type>::iterator i=vect.begin(); i!=vect.end(); ++i ) { \
    __VA_ARGS__ \
  }

int main()
{
    std::vector<int> v = {1, 2, 3, 4, 5, 6};
    FOR_VECTOR(int, v, {
        std::cout << *i << std::endl;
    })
}

你可以在这里在线玩它:https://godbolt.org/z/oLWV-z

我在这里找到了解决方案:https://mort.coffee/home/obscure-c-features/

您还可以制作更通用的FOR_CONTAINER 宏:

#include <iostream>
#include <vector>

#define FOR_CONTAINER( container, ... ) \
  for( decltype(container)::iterator i=container.begin(); i!=container.end(); ++i ) { \
    __VA_ARGS__ \
  }

int main()
{
    std::vector<int> v = {1, 2, 3, 4, 5, 6};
    FOR_CONTAINER(v, {
        std::cout << *i << std::endl;
    })
}

在这里试试:https://godbolt.org/z/9Gzqja

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-14
    • 1970-01-01
    • 1970-01-01
    • 2021-07-18
    • 1970-01-01
    • 2013-04-02
    相关资源
    最近更新 更多