Pranav Gulati Pranav Gulati - 1 month ago 12
C++ Question

Using Macros to select function arguments

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


now if when i call a function that takes 3 arguments all of type int
foo(int,int,int);
like this
foo(PINS1);
then the function compiles and works as expected(all arguments are passed as if the #define was replaced by "5,6,7")

but if i use the macro for selecting the set of pins like
foo(PINS(STRIP1));
then the argument selection goes haywire. in this specific case the faulty argument list becomes "7,12,13" and for
foo(PINS(STRIP0));
it becomes "4,12,13" there is a pattern that i see but i dont have the expertise to tell and rectify what is happening at compile time.

Answer

Imo you're hurting readability a lot by using macros for this. But here's how I'd do this:

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

now, you'd call this like this:

PINS(foo, STRIP0);

demo

You need two levels of indirection, because of the way macro replacement works (here is an in-depth explanation). With just #define CONCAT(A,B) A ## B, CONCAT(PINS,STRIP0) would create PINSSTRIP0 which makes no sense here.


For completeness sake, if you expect to use this with runtime values (of which you gave no indication of in the question), you could go with a helper function template that would switch over the strip value:

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

and, if you have C++17 available:

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

though at this point, the helper function stops being necessary.

Comments