问题
Because someone in our group hates exceptions (let's not discuss that here), we tend to use error-checking macros in our C++ projects. I have encountered an odd compilation failure when using a templated function with two type parameters. There are a few errors (below), but I think the root cause is a warning:
warning C4002: too many actual parameters for macro 'BOOL_CHECK_BOOL_RETURN'
Probably best explained in code:
#include "stdafx.h"
template<class A, class B>
bool DoubleTemplated(B & value)
{
return true;
}
template<class A>
bool SingleTemplated(A & value)
{
return true;
}
bool NotTemplated(bool & value)
{
return true;
}
#define BOOL_CHECK_BOOL_RETURN(expr) \
do \
{ \
bool __b = (expr); \
if (!__b) \
{ \
return false; \
} \
} while (false) \
bool call()
{
bool thing = true;
// BOOL_CHECK_BOOL_RETURN(DoubleTemplated<int, bool>(thing));
// Above line doesn't compile.
BOOL_CHECK_BOOL_RETURN((DoubleTemplated<int, bool>(thing)));
// Above line compiles just fine.
bool temp = DoubleTemplated<int, bool>(thing);
// Above line compiles just fine.
BOOL_CHECK_BOOL_RETURN(SingleTemplated<bool>(thing));
BOOL_CHECK_BOOL_RETURN(NotTemplated(thing));
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
call();
return 0;
}
Here are the errors, when the offending line is not commented out:
1>------ Build started: Project: test, Configuration: Debug Win32 ------
1>Compiling...
1>test.cpp
1>c:\junk\temp\test\test\test.cpp(38) : warning C4002: too many actual parameters for macro 'BOOL_CHECK_BOOL_RETURN'
1>c:\junk\temp\test\test\test.cpp(38) : error C2143: syntax error : missing ',' before ')'
1>c:\junk\temp\test\test\test.cpp(38) : error C2143: syntax error : missing ';' before '{'
1>c:\junk\temp\test\test\test.cpp(41) : error C2143: syntax error : missing ';' before '{'
1>c:\junk\temp\test\test\test.cpp(48) : error C2143: syntax error : missing ';' before '{'
1>c:\junk\temp\test\test\test.cpp(49) : error C2143: syntax error : missing ';' before '{'
1>c:\junk\temp\test\test\test.cpp(52) : error C2143: syntax error : missing ';' before '}'
1>c:\junk\temp\test\test\test.cpp(54) : error C2065: 'argv' : undeclared identifier
1>c:\junk\temp\test\test\test.cpp(54) : error C2059: syntax error : ']'
1>c:\junk\temp\test\test\test.cpp(55) : error C2143: syntax error : missing ';' before '{'
1>c:\junk\temp\test\test\test.cpp(58) : error C2143: syntax error : missing ';' before '}'
1>c:\junk\temp\test\test\test.cpp(60) : error C2143: syntax error : missing ';' before '}'
1>c:\junk\temp\test\test\test.cpp(60) : fatal error C1004: unexpected end-of-file found
1>Build log was saved at "file://c:\junk\temp\test\test\Debug\BuildLog.htm"
1>test - 12 error(s), 1 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Any ideas? Thanks!
回答1:
Macros are unaware of the language, and work only with lexical tokens. A comma separates arguemnts for a macro, thus the following code attemps to 'invoke' the macro with two arguments:
BOOL_CHECK_BOOL_RETURN(DoubleTemplated<int, bool>(thing));
DoubleTemplated<int
and bool>(thing)
. That's the warning you are seeing, and cause of the other errors as well. The following is the correct way to protect against ,
in template arguments list:
BOOL_CHECK_BOOL_RETURN((DoubleTemplated<int, bool>(thing)));
回答2:
The preprocessor has no understanding of C++! It simply performs lexical substitutions.
When you declare a multi-argument macro, the arguments are separated by a comma. Since you have a comma in your macro invocation, you're calling the macro with multiple parameters, despite it being declared to only take one argument.
Parentheses are understood by the PP as forming a token group, so everything inside a set of parentheses is one big token.
回答3:
In the line that doesn't compile, that comma is interpreted by the preprocessor as a delimiter of the macro arguments.
In the C99 standard (I haven't got the C++ standard to hand, but it will be very similar), we see the following in section 6.10.3:
The sequence of preprocessing tokens bounded by the outside-most matching parentheses forms the list of arguments for the function-like macro. The individual arguments within the list are separated by comma preprocessing tokens, but comma preprocessing tokens between matching inner parentheses do not separate arguments.
So that's why your second macro instantiation works.
来源:https://stackoverflow.com/questions/8101868/templated-function-with-two-type-parameters-fails-compile-when-used-with-an-erro