【问题标题】:Strange behaviour with templates and #defines模板和#defines 的奇怪行为
【发布时间】:2010-07-06 12:44:52
【问题描述】:

我有以下定义:

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 会发生这种情况。

【问题讨论】:

  • 这可能会发生,因为您在 VERIFY_R 的 () 中放入的任何内容都是按字面意思插入的。尝试将宏中的第二个“调用”更改为“(调用)”。
  • 这无济于事,这是一个宏观问题。有趣的是:这就是为什么BOOST_FOREACH 会让新手头疼:)

标签: c++ templates visual-studio-2008 syntax c-preprocessor


【解决方案1】:

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

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

那么你可以写VERIFY( foo&lt;bar, x&gt; y )

另一种消除歧义的方法是使用

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

【讨论】:

    【解决方案2】:

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

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

    作为

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

    使用太多参数调用VERIFY_R。正如你所指出的,额外的括号解决了这个问题:

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

    但是,问题仍然存在,为什么您仍然需要预处理器。您在问题中使用的宏也可以是 inline 函数。如果您的真实代码不需要预处理器,请尝试摆脱宏。它们只会引起疼痛。

    【讨论】:

      【解决方案3】:

      &lt;int, int&gt; 中的逗号被视为宏的参数分隔符,而不是模板的分隔符。因此,编译器认为您使用两个参数(Test1&lt;intint&gt;::hello())调用 VERIFY_R,而它只需要一个参数。您需要使用variadic macros 来扩展提供给宏的所有内容:

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

      通常最好将宏参数括在括号中,以防止其他类型的奇怪替换错误。

      【讨论】:

        【解决方案4】:

        预处理器不知道&lt;&gt; 应该是括号,因此它将表达式解释为两个宏参数Test1&lt;intint&gt;::hello(),由, 分隔。正如您所说,可以通过用括号将整个表达式括起来来修复它,预处理器确实将其识别为括号。

        【讨论】:

          【解决方案5】:

          我不确定这是您在此处报告的错误还是实际问题,但您的最后一个 VERIFY_R 仍然引用 Test1,而不是 Test2。

          【讨论】:

            猜你喜欢
            • 2011-08-06
            • 1970-01-01
            • 2023-03-26
            • 1970-01-01
            • 1970-01-01
            • 2011-03-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多