【问题标题】:Using Macros to select function arguments使用宏选择函数参数
【发布时间】:2016-10-30 06:14:45
【问题描述】:
#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}

现在,如果当我调用一个接受 3 个参数的函数时,所有参数都是 int foo(int,int,int); 这样的 foo(PINS1);,那么该函数将按预期编译和工作(所有参数都被传递,就好像 #define 被替换为 "5, 6,7")

但是如果我使用宏来选择像foo(PINS(STRIP1)); 这样的引脚集,那么参数选择就会变得混乱。在这种特定情况下,错误参数列表变为“7,12,13”,对于foo(PINS(STRIP0));,它变为“4,12,13”,我看到了一种模式,但我没有专业知识来告诉和纠正正在发生的事情在编译时。

【问题讨论】:

  • 如果你使用 PINS 类函数宏,你会遇到两个问题:第一个是整个表达式周围的花括号,第二个是你传递的不是多个参数,而是一个单个参数,因为逗号不再是参数分隔符,而是逗号表达式。您应该重新考虑使用宏,是否可以使用 inline 函数包装器?或者至少修改宏,也许将函数作为参数并在宏“body”中调用?
  • 你为什么不写一个if/else
  • @Someprogrammerdude 我将删除花括号并编辑问题,但它对输出没有影响。当我这样做foo(PINS1);(如问题中所指定)时,函数本身将3个数字作为参数,这使我相信逗号作为表达式没有发生,而是编译器识别出有3个参数,这就是它继续进行的原因。这就是我认为做一个选择PINS0PINS1 的宏会起作用但没有用的原因。您建议将函数作为宏中的参数可能是 krzaq 的建议

标签: c++ gcc macros arduino


【解决方案1】:

Imo 您为此使用宏会严重损害可读性。但我会这样做:

#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))

现在,你可以这样称呼:

PINS(foo, STRIP0);

demo

由于宏替换的工作方式,您需要两个间接级别(here 是一个深入的解释)。仅使用 #define CONCAT(A,B) A ## BCONCAT(PINS,STRIP0) 将创建 PINSSTRIP0,这在这里没有意义。


为了完整起见,如果您希望将其与运行时值一起使用(您在问题中没有给出任何指示),您可以使用一个可以切换条带值的辅助函数模板:

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

demo

如果你有 C++17 可用:

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

demo

尽管此时,辅助函数不再是必要的。

【讨论】:

  • 我绝对需要我的咖啡。很好的答案,但也许有必要解释 为什么 需要中间扩展。 OP好像不太精通。
  • @StoryTeller 添加了。
  • 我试图实现的目标是每个 PINS0 集对应于一组不同的物理引脚连接,这些连接在运行时不会改变,需要作为参数传递给各种函数,所以这样做像这样的东西,我将省去在任何地方更改这些定义的麻烦,仅此而已!我会试试你的答案,看起来应该可以@StoryTeller我不是很精通,当然感谢大家的帮助;-)
猜你喜欢
  • 2021-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-16
  • 2014-04-20
相关资源
最近更新 更多