Home > Software engineering >  C Overloading macro on undefined number of arguments
C Overloading macro on undefined number of arguments

Time:02-13

My command uses return codes and a string reference argument instead of exceptions to detect an error in the execution of a function.

We have some invariant checking that looks like this:

bool format(std::string &error, ...)
{
    // call sprintf on "error" string with all passed arguments
    return false;
}

bool func(std::string &error)
{
    // .......................
    
    if (!some_expression)
        return format(error, /*some undefined number of args*/);    
    
    // .......................
}
    

I want to write a macro, that will perform this logic in one line like this:

REQUIRE(expr, functor, "test string");
REQUIRE(expr, functor, "number=%lld", 1ll);
REQUIRE(expr, functor, "number_1=%lld, number_2=%f", 1ll, 2.0);

When REQUIRE macro will be this:

#define REQUIRE(expression, functor, format, ...)   \
{                                                   \
    if (!expression)                                \
        return functor(format, __VA_ARGS__)         \
}   

But this solution doesn't work, when i pass only format string without any arguments (first case in example). I tryed all solutions from this question: Overloading Macro on Number of Arguments, but all of them requires writing overloading on all agrs count.

Here is my non-working code code for now:

#define REQUIRE_1(expression, functor, format)  \
{                                               \
    if (!expression)                            \
        return functor(format);                 \
} 

#define REQUIRE_2(expression, functor, format, ...) \
{                                                   \
    if (!expression)                                \
        return functor(format, __VA_ARGS__)         \
}   

#define GET_MACRO(_1, _2, _3, NAME, ...) NAME
#define REQUIRE(...) GET_MACRO(__VA_ARGS__, REQUIRE_1, REQUIRE_2)(__VA_ARGS__)
                                        
bool functor(const char *format, ...)
{
    // Here is passing args to something like printf

    return false;
}


bool format(std::string &error, ...)
{
    // call sprintf on "error" string with all passed arguments
    return false;
}

bool func(std::string &error)
{
    // .......................

    if (!some_expression)
        return format(error, /*some undefined number of args*/);    

    // .......................
}



int main()
{
    REQUIRE(true, func, "test string");
    REQUIRE(true, func, "number=%lld", 1ll);
    REQUIRE(true, func, "number_1=%lld, number_2=%f", 1ll, 2.0);
    // Samples for [5,6,7..infinite] arguments
}

How can i achieve needed behaviour?

CodePudding user response:

C 20 made it possible to call #define F(x, y, ...) as F(1, 2), without the comma after the last argument.

If C 20 is available, the only change you need to do is to replace , __VA_ARGS__ with __VA_OPT__(,) __VA_ARGS__ to the remove the comma if no extra arguments are passed.

Otherwise, just combine format and ... parameters into a single ... parameter.

  •  Tags:  
  • c
  • Related