【问题标题】:C++ preprocessors are not aware of template arguments?C++ 预处理器不知道模板参数?
【发布时间】:2015-11-21 09:01:11
【问题描述】:

看起来,如果带有多个参数的模板实例化作为参数传递给宏,则 C++ 预处理器会失败。

请参阅下面的示例。

#include <stdio.h>

#define FOO(v) printf("%d\n",v::val())

template<int N>
struct bar {
    static int val() { return N; }
};
template<int N, int M>
struct baz {
    static int val() { return N+M; }
};

int main() {
    printf("%d\n",bar<1>::val());
    printf("%d\n",baz<1,2>::val());
    FOO(bar<10>);       // OK
    FOO(baz<20,30>);    // error: too many arguments provided to function-like macro invocation
    FOO((baz<20,30>));  // error: '::val' has not been declared
}

Tested 与 clang++ 和 g++

是否应该将其视为错误?

【问题讨论】:

  • 你可以设计宏来提取括号内的参数,但是这个例子当然不需要宏。
  • 一个相关问题:C++ 预处理器是否知道 C++? AFAICT C++ 预处理器并没有太大变化,因为它只是 C 预处理器...... ;)
  • @chris,谢谢,根据您的消息中的措辞,我找到了类似问题的答案stackoverflow.com/questions/13842468/comma-in-c-c-macro/…
  • 这个链接不错,谢谢转发
  • 预处理器对 C++ 语法一无所知,它是一个非常愚蠢的宏处理器,遵循非常简单的规则。

标签: c++ templates parameters arguments c-preprocessor


【解决方案1】:

不,这不是错误。

c 预处理器与其他语言不同,它按照自己的规则运行。改变这一点会极大地破坏兼容性,CPP 是高度严格标准化的。

解决这些逗号问题的常用方法是,

typedef baz<20,30> baz2030_type;
FOO(baz2030_type);

【讨论】:

    【解决方案2】:

    C/C++ 预处理器将逗号识别为宏参数分隔符,除非它们嵌套在括号内。只是括号。方括号、大括号和模板标记不计算在内:

    列表中的各个参数由逗号预处理标记分​​隔,但匹配内括号之间的逗号预处理标记不分隔参数。 (C++14 §16.3/11;C11 §6.10.3/11)

    (上面的一个副作用是您可以使用不平衡的大括号和方括号作为宏参数。这通常不是一个好主意,但如果必须,您可以这样做。)

    结果偶尔会出现问题;当参数应该是代码块时,一个常见的参数是不需要的多个参数:

    MY_FANCY_MACRO(1000, { int i=0, j=42; ... })
    

    这里,宏是用(至少)3 个参数调用的,尽管它可能被编写为接受 2 个。

    使用现代 C++(和 C)编译器,您有几个选择。以相当主观的顺序:

    1. 将宏重写为内联函数。如果参数是代码块,请考虑使用可以接受 lambda 或其他仿函数的模板化函数。如果参数是类型,请将其改为模板参数。

    2. 如果用多余的括号括起来的参数在语法上是有效的,那么就这样做。但在这种情况下,几乎可以肯定上述建议 (1) 会奏效。

    3. 定义:

      #define COMMA ,
      

      并在必要时使用它:

       FOO(baz<20 COMMA 30>);
      

      这不需要以任何方式修改宏定义,但如果宏将参数传递给另一个宏,它将失败。 (替换将在解析内部宏调用之前完成,因此多参数问题将推迟到内部调用。)

    4. 如果您希望一个宏参数可能包含不受保护的逗号,并且它是最后一个或唯一一个参数,并且您可以修改宏,并且您使用的是 C++11/C99 或更好的 (或 gcc,它允许将其作为扩展已有一段时间),使宏可变参数:

      #define FOO(...) printf("%d\n",__VA_ARGS__::val())
      

    【讨论】:

      【解决方案3】:

      宏的参数被视为纯文本字符串,参数使用逗号分隔。因此,模板中的逗号将被视为分隔符。因此,预处理器会认为您已将两个参数传递给单个参数宏,因此会出现错误。

      【讨论】:

        猜你喜欢
        • 2016-06-30
        • 2010-11-11
        • 2021-01-08
        • 2011-02-23
        • 2011-04-26
        • 2015-09-13
        • 1970-01-01
        • 1970-01-01
        • 2011-01-08
        相关资源
        最近更新 更多