C / C ++预处理器:提取每隔一个可变参数

时间:2017-08-18 12:40:34

标签: c++ c-preprocessor variadic-macros

有没有办法从C / C ++预处理器中的可变参数列表中提取每个第二个参数?

我想用以下方式编写一个宏来为接口方法生成样板代码:

sourceMat

将用作:

#define INTERFACE_FN(_NAME, _X, _Y, _N_PARAMS, ...) \
    void _NAME(__VA_ARGS__) \
    { \
        processing_function(_X, _Y, _N_PARAMS, EVERY_SECOND(__VA_ARGS__); \
    }

void processing_function(int x, int y, int count, ...)
{
    va_list params;
    va_start(params, count);
    while (count--) {
        do_something(va_arg(params, ParentClass*));
    }
    va_end(params);
    // do something else
}

课程INTERFACE_FN(foo, 1, 2, 0); INTERFACE_FN(bar, 3, 4, 1, ClassX*, x); INTERFACE_FN(jar, 5, 6, 2, ClassY*, y, ClassZ*, z); ClassXClassYClassZ的衍生工具;

我正在寻找ParentClass宏。

1 个答案:

答案 0 :(得分:1)

以下是您要求的

的工作示例
#define EVERY_SECOND0(...)

#define EVERY_SECOND1_(second, ...) , second
#define EVERY_SECOND1(first, ...) EVERY_SECOND1_(__VA_ARGS__)

#define EVERY_SECOND2_(second, ...) , second EVERY_SECOND1(__VA_ARGS__)
#define EVERY_SECOND2(first, ...) EVERY_SECOND2_(__VA_ARGS__)

#define EVERY_SECOND3_(second, ...) , second EVERY_SECOND2(__VA_ARGS__)
#define EVERY_SECOND3(first, ...) EVERY_SECOND3_(__VA_ARGS__)

#define EVERY_SECOND4_(second, ...) , second EVERY_SECOND3(__VA_ARGS__)
#define EVERY_SECOND4(first, ...) EVERY_SECOND4_(__VA_ARGS__)

#define EVERY_SECOND5_(second, ...) , second EVERY_SECOND4(__VA_ARGS__)
#define EVERY_SECOND5(first, ...) EVERY_SECOND5_(__VA_ARGS__)

#define COUNT_EVERY_SECOND(_1,__1,_2,__2,_3,__3,_4,__4,_5,__5,num,...) EVERY_SECOND ## num
#define EVERY_SECOND(...) COUNT_EVERY_SECOND(__VA_ARGS__,5,5,4,4,3,3,2,2,1,0)(__VA_ARGS__)


#define INTERFACE_FN(_NAME, _X, _Y, _N_PARAMS, ...) \
    void _NAME(__VA_ARGS__) \
    { \
        processing_function(_X, _Y, _N_PARAMS EVERY_SECOND(__VA_ARGS__)); \
    }

class parentClass {};
class ClassX {};
class ClassY {};
class ClassZ {};

void processing_function(int x, int y, int count, ...)
{
    va_list params;
    va_start(params, count);
    while (count--) {
        do_something(va_arg(params, ParentClass*));
    }
    va_end(params);
    // do something else
}

INTERFACE_FN(foo, 1, 2, 0);
INTERFACE_FN(bar, 3, 4, 1, ClassX*, x);
INTERFACE_FN(jar, 5, 6, 2, ClassY*, y, ClassZ*, z);

预处理器输出如下所示

class parentClass {};
class ClassX {};
class ClassY {};
class ClassZ {};

void processing_function(int x, int y, int count, ...)
{
 va_list params;
 va_start(params, count);
 while (count--) {
  do_something(va_arg(params, ParentClass*));
 }
 va_end(params);

}

void foo() { processing_function(1, 2, 0 ); };
void bar(ClassX*, x) { processing_function(3, 4, 1 , x); };
void jar(ClassY*, y, ClassZ*, z) { processing_function(5, 6, 2 , y , z); };

虽然我会给出强制性的警告,即如果没有宏,可能会有更简单的方法来做到这一点。

如果您输入奇数个参数,最后会有一个额外的逗号,但这不应该发生在您的用例中。这允许最多5对(总共10个参数),但我认为您可以看到如何添加更多支持的模式。如果没有明确定义由于预处理器限制而导致的每个args数量

,则无法执行此操作

玩得开心!

编辑:

我还要注意,这可以改进,以便您永远不必指定_N_PARAMS并让宏为您计算,只需添加一个宏

#define COUNT_EVERY_SECOND_(_1,__1,_2,__2,_3,__3,_4,__4,_5,__5,num,...) num

并用此

替换INTERFACE_FN的定义
#define INTERFACE_FN(_NAME, _X, _Y, ...) \
    void _NAME(__VA_ARGS__) \
    { \
        processing_function(_X, _Y, COUNT_EVERY_SECOND_(__VA_ARGS__,5,ERROR,4,4,3,3,2,2,1,0) EVERY_SECOND(__VA_ARGS__)); \
    }