C++ 使用宏选择函数参数
现在,如果我调用一个包含3个参数的函数,所有类型都是intC++ 使用宏选择函数参数,c++,gcc,macros,arduino,C++,Gcc,Macros,Arduino,现在,如果我调用一个包含3个参数的函数,所有类型都是intfoo(int,int,int)像这样foo(PINS1)然后函数按照预期编译和工作(所有参数都被传递,就好像#define被替换为“5,6,7”) 但是如果我使用宏来选择引脚集,比如foo(pins(STRIP1))然后参数选择就乱了套。在这种特定情况下,错误参数列表变为“7,12,13”,对于foo(PINS(STRIP0))它变成了“4,12,13”。我看到了一种模式,但我没有专业知识来告诉和纠正编译时发生的事情。我认为,使用宏来实
foo(int,int,int)代码>像这样foo(PINS1)
然后函数按照预期编译和工作(所有参数都被传递,就好像#define被替换为“5,6,7”)
但是如果我使用宏来选择引脚集,比如foo(pins(STRIP1))代码>然后参数选择就乱了套。在这种特定情况下,错误参数列表变为“7,12,13”,对于foo(PINS(STRIP0))代码>它变成了“4,12,13”。我看到了一种模式,但我没有专业知识来告诉和纠正编译时发生的事情。我认为,使用宏来实现这一点会严重损害可读性。但我会这样做:
#define STRIP0 0
#define STRIP1 1
#define STRIP2 2
#define STRIP3 3
#define PINS0 2,3,4
#define PINS1 5,6,7
#define PINS2 8,9,10
#define PINS3 11,12,13
#define PINS(STRIP) { (STRIP) == (STRIP0) ? PINS0 :\
(STRIP) == (STRIP1) ? PINS1 :\
(STRIP) == (STRIP2) ? PINS2 :PINS3}
现在,你可以这样称呼它:
#define STRIP0 0
#define STRIP1 1
#define STRIP2 2
#define STRIP3 3
#define PINS0 2,3,4
#define PINS1 5,6,7
#define PINS2 8,9,10
#define PINS3 11,12,13
#define CONCAT_HELP(A, B) A ## B
#define CONCAT(A, B) CONCAT_HELP(A, B)
#define PINS(FUNC,STRIP) FUNC(CONCAT(PINS, STRIP))
由于宏替换的工作方式,您需要两个级别的间接寻址(这是一个深入的解释)。只要#定义CONCAT(A,B)A##B
,CONCAT(PINS,STRIP0)
就会创建PINSSTRIP0
,这在这里没有意义
为了完整性起见,如果您希望将其用于运行时值(您在问题中没有给出该值的指示),则可以使用一个助手函数模板来切换strip值:
PINS(foo, STRIP0);
模板
空心管脚(函数f,int-strip)
{
开关(带){
案例0:f(PINS0);断裂;
案例1:f(销1);断裂;
案例2:f(销2);断裂;
案例3:f(销3);断裂;
}
}
并且,如果您有C++17可用:
template<typename Func>
void pins(Func f, int strip)
{
switch(strip){
case 0: f(PINS0); break;
case 1: f(PINS1); break;
case 2: f(PINS2); break;
case 3: f(PINS3); break;
}
}
constexpr元组参数[]={
制作元组(PINS0),
制作元组(PINS1),
制作元组(PINS2),
制作元组(PINS3)
};
模板
空心管脚(函数f,int-strip)
{
应用(f,参数[strip]);
}
尽管在这一点上,helper函数不再是必需的。如果使用类似于宏的PINS
函数,您会遇到两个问题:第一个是整个表达式周围的大括号,第二个是,不是传递多个参数,而是传递一个参数,因为这样逗号就不是参数分隔符,而是逗号表达式。您应该重新考虑宏的使用,是否可以使用inline
函数包装器?或者至少修改宏,或者将函数作为参数,并将调用放在宏“body”中?为什么不编写一个if/else
@Someprogrammerdude?我将删除大括号并编辑问题,但它对输出没有影响。当我这样做foo(PINS1)代码>(如问题中所述)函数本身将3个数字作为参数,这使我相信逗号作为表达式并没有发生,而编译器认识到有3个参数,这就是为什么它继续进行。这就是我认为选择PINS0
或PINS1
的宏可以工作的原因,但事实并非如此。你建议将函数作为宏中的参数,这可能是krzaq建议的,我确实需要我的咖啡。很好的回答,但解释为什么需要中间扩展可能是相关的。OP似乎不太精通。@StoryTeller补充道。我试图实现的目标是,每个PINS0集对应于一组不同的物理pin连接,这些物理pin连接在运行时不会更改,需要作为参数传递给各个函数,因此通过这样做,我将省去更改这些连接的麻烦定义无处不在,仅此而已!我会试试你的答案,看起来应该有用@StoryTeller我不太精通,谢谢大家的帮助;-)
constexpr tuple<int,int,int> params[] = {
make_tuple(PINS0),
make_tuple(PINS1),
make_tuple(PINS2),
make_tuple(PINS3)
};
template<typename Func>
void pins(Func f, int strip)
{
apply(f, params[strip]);
}