Question

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 '}'
Was it helpful?

Solution

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.

OTHER TIPS

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.

Instead of the __VA_ARGS__ trick, you can also use a typedef before the macro. The __VA_ARGS__ trick has some drawbacks.

typedef std::map<MyType, bool> MyMap;

TRAP_EXCEPTION(
  MyMap Map;
)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top