views:

80

answers:

5

I have the following definitions:

template<typename T1, typename T2>
class Test2
{
public:
    static int hello() { return 0; }
};

template<typename T>
class Test1
{
public:
    static int hello() { return 0; }
};

#define VERIFY_R(call) { if (call == 0) printf("yea");}

With these, I try to compile the following:

VERIFY_R( Test1<int>::hello() ); 

this compiles fine

VERIFY_R( (Test2<int,int>::hello()) );

this also compiles fine, notice the parentheses around the call.

VERIFY_R( Test2<int,int>::hello() );

This, without the parentheses produces a warning and several syntax errors:

warning C4002: too many actual parameters for macro 'VERIFY_R'
error C2143: syntax error : missing ',' before ')'
error C2059: syntax error : ')'
error C2143: syntax error : missing ';' before '}'
error C2143: syntax error : missing ';' before '}'
error C2143: syntax error : missing ';' before '}'
fatal error C1004: unexpected end-of-file found    

What's going on here?
This happens with VS2008 SP1.

+3  A: 

The comma in <int, int> is treated as an argument separator for the macro, rather than for the template. The compiler therefore thinks you're calling VERIFY_R with two arguments (Test1<int and int>::hello()), when it requires only one. You need to use variadic macros to expand everything supplied to the macro:

#define VERIFY_R(...) { if ((__VA_ARGS__) == 0) printf("yea");}

It is generally a good idea to wrap macro arguments in parentheses, as well, to prevent other kinds of weird substitution errors.

Jon Purdy
A: 

I'm not sure if this is an error in your reporting here or the actual problem, but your last VERIFY_R is still referencing Test1, rather than Test2.

Colin DeClue
+5  A: 

The preprocessor is a dumb text replacement tool that knows nothing about C++. It interprets

VERIFY_R( Test1<int,int>::hello() );

as

VERIFY_R( (Test1<int), (int>::hello()) );

which calls VERIFY_R with too many parameters. As you noted, additional parentheses fix this:

VERIFY_R( (Test1<int,int>::hello()) );

The question remains, however, why you need the preprocessor anyway. The macro you used in your question could just as well be an inline function. If you real code doesn't do anything requiring the preprocessor, try to get rid of macros. They just cause pain.

sbi
+3  A: 

The preprocessor doesn't know that < and > are supposed to be brackets, so it interprets the expression as two macro arguments, Test1<int and int>::hello(), separated by the ,. As you say, it can be fixed by surrounding the entire expression with parentheses, which the preprocessor does recognise as brackets.

Mike Seymour
+5  A: 

The comma inside a macro can be ambiguous: an extra set of parentheses (your second example) is one way of disambiguating. Consider a macro

#define VERIFY(A, B) { if ( (A) && (B) ) printf("hi"); }

then you could write VERIFY( foo<bar, x> y ).

Another way of disambiguating is with

typedef Test1<int,int> TestII;
VERIFY_R( TestII::hello() );
Seth Johnson