我有以下定义:
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");}
有了这些,我尝试编译以下内容:
VERIFY_R( Test1<int>::hello() );
这个编译很好
VERIFY_R( (Test2<int,int>::hello()) );
这也编译得很好,注意电话周围的括号。
VERIFY_R( Test2<int,int>::hello() );
如果没有括号,会产生警告和几个语法错误:
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
这里发生了什么事? 这种情况发生在VS2008 SP1上。
答案 0 :(得分:6)
宏中的逗号可能不明确:一组额外的括号(第二个示例)是一种消除歧义的方法。考虑一个宏
#define VERIFY(A, B) { if ( (A) && (B) ) printf("hi"); }
然后你可以写VERIFY( foo<bar, x> y )
。
另一种消除歧义的方法是使用
typedef Test1<int,int> TestII;
VERIFY_R( TestII::hello() );
答案 1 :(得分:5)
预处理器是一个愚蠢的文本替换工具,对C ++一无所知。它解释了
VERIFY_R( Test1<int,int>::hello() );
as
VERIFY_R( (Test1<int), (int>::hello()) );
使用太多参数调用VERIFY_R
。如您所述,其他括号修复此问题:
VERIFY_R( (Test1<int,int>::hello()) );
然而,问题仍然是为什么你需要预处理器。您在问题中使用的宏也可以是inline
函数。如果您的实际代码不执行任何需要预处理器的操作,请尝试删除宏。他们只会引起疼痛。
答案 2 :(得分:4)
<int, int>
中的逗号被视为宏的参数分隔符,而不是模板。因此,编译器认为您使用两个参数(VERIFY_R
和Test1<int
)调用int>::hello()
,只需要一个参数。您需要使用variadic macros来扩展提供给宏的所有内容:
#define VERIFY_R(...) { if ((__VA_ARGS__) == 0) printf("yea");}
通常,在括号中包装宏参数也是一个好主意,以防止其他类型的奇怪替换错误。
答案 3 :(得分:3)
预处理器不知道<
和>
应该是括号,因此它将表达式解释为两个宏参数Test1<int
和int>::hello()
,分开由,
。如您所说,可以通过用括号括起整个表达式来修复它,预处理器将其识别为括号。
答案 4 :(得分:0)
我不确定这是您的报告中的错误还是实际问题,但您的上一次VERIFY_R仍然是引用Test1而不是Test2。