模板和#defines的奇怪行为

sho*_*osh 0 c++ syntax templates visual-studio-2008 c-preprocessor

我有以下定义:

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");}
Run Code Online (Sandbox Code Playgroud)

有了这些,我尝试编译以下内容:

VERIFY_R( Test1<int>::hello() ); 
Run Code Online (Sandbox Code Playgroud)

编译好了

VERIFY_R( (Test2<int,int>::hello()) );
Run Code Online (Sandbox Code Playgroud)

这也编译得很好,注意电话周围的括号.

VERIFY_R( Test2<int,int>::hello() );
Run Code Online (Sandbox Code Playgroud)

没有括号的这会产生警告和几个语法错误:

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    
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?
这种情况发生在VS2008 SP1上.

Set*_*son 6

宏中的逗号可能不明确:一组额外的括号(第二个示例)是一种消除歧义的方法.考虑一个宏

#define VERIFY(A, B) { if ( (A) && (B) ) printf("hi"); }
Run Code Online (Sandbox Code Playgroud)

然后你可以写VERIFY( foo<bar, x> y ).

消除歧义的另一种方法是

typedef Test1<int,int> TestII;
VERIFY_R( TestII::hello() );
Run Code Online (Sandbox Code Playgroud)


sbi*_*sbi 5

预处理器是一个愚蠢的文本替换工具,对C++一无所知.它解释

VERIFY_R( Test1<int,int>::hello() );
Run Code Online (Sandbox Code Playgroud)

VERIFY_R( (Test1<int), (int>::hello()) );
Run Code Online (Sandbox Code Playgroud)

调用VERIFY_R参数太多.如您所述,其他括号修复此问题:

VERIFY_R( (Test1<int,int>::hello()) );
Run Code Online (Sandbox Code Playgroud)

然而,问题仍然是,为什么你还需要预处理器.您在问题中使用的宏也可以是一个inline函数.如果您真正的代码不执行任何需要预处理器的操作,请尝试去掉宏.它们只会引起疼痛.