Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

C++ Overloading macro on undefined number of arguments

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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?

>Solution :

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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading