Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Macro taking code statement as argument fails when std::map is present

I have a macro used around a code statement, to introduce nested exception handling:

#define TRAP_EXCEPTION(statement) \
    try \
    { \
        try{statement} \
        catch(Engine::Exception& e) \
        { \
            throw MyException(e.message()); \
        } \
    }

This has been working well until one case raised compiler errors. I managed to construct a minimal example:

TRAP_EXCEPTION
(
 std::map<MyType, bool> Map;
)
catch(MyException& e)
{
}

This gives the following errors... how do I fix it (ideally in the macro)?

> error C2143: syntax error : missing '>' before '}'
> error C2976: 'std::map' : too few template arguments
> error C2143: syntax error : missing ';' before '}'
like image 265
Mr. Boy Avatar asked Dec 19 '22 15:12

Mr. Boy


2 Answers

Macros don't understand the template parameters (the angle brackets to be precise), they just see the , and think you provided two different parameters to the macro. You need to add round brackets:

TRAP_EXCEPTION
(
    (std::map<MyType, bool> Map;)
)

and the macro needs to be changed:

#define UNWRAP(...) __VA_ARGS__

#define TRAP_EXCEPTION(statement) \
    try \
    { \
        try{UNWRAP statement} \
        catch(Engine::Exception& e) \
        { \
            throw MyException(e.message()); \
        } \
    }

Note that this would require you to always provide an additional pair of round brackets on the call side.

In your case (since the macro is supposed to take only one statement), you could also use a variadic macro:

#define TRAP_EXCEPTION(...) \
    try \
    { \
        try{ __VA_ARGS__ } \
        catch(Engine::Exception& e) \
        { \
            throw MyException(e.message()); \
        } \
    }

which is probably better since the call side doesn't change and

TRAP_EXCEPTION
(
    std::map<MyType, bool> Map;
)

will now work correctly.

like image 59
Daniel Frey Avatar answered Feb 23 '23 00:02

Daniel Frey


The preprocessor doesn't recognise < and > as brackets, so interprets the comma as a macro argument separator. You'd have the same problem if the statement contained an unbracketed comma for any other reason (e.g. a comma operator, or commas to separate declarators).

If you really want to abuse the preprocessor like this, you could bodge it to accept any number of macro arguments:

#define TRAP_EXCEPTION(...) \
try \
{ \
    try{__VA_ARGS__} \
    catch(Engine::Exception& e) \
    { \
        throw MyException(e.message()); \
    } \
}

but I would advise you not to try to do anything clever with macros.

like image 40
Mike Seymour Avatar answered Feb 22 '23 23:02

Mike Seymour