【问题标题】:Are empty macro arguments legal in C++11?C++11 中的空宏参数是否合法?
【发布时间】:2011-12-01 18:06:02
【问题描述】:

我有时会故意省略宏参数。例如,对于类似函数的宏,如

#define MY_MACRO(A, B, C)  ...

我可以这样称呼它:

MY_MACRO(, bar, baz)

技术上仍有 3 个参数;只是第一个是“空的”。这个问题与可变参数宏无关。

当我这样做时,我会在使用 -ansi(又名 -std=c++98)进行编译时收到来自 g++ 的警告,但在我使用 -std=c++0x 时不会收到警告。这是否意味着空宏参数在新的 C++ 标准中是合法的?

这就是我的全部问题,但期待“你为什么要这样做?”回应,这是一个例子。我喜欢保持 .h 文件不受函数体的干扰,但是在 .h 文件之外实现简单的访问器是乏味的。因此,我编写了以下宏:

#define IMPLEMENT_ACCESSORS(TEMPLATE_DECL, RETURN_TYPE, CLASS, FUNCTION, MEMBER) \
  TEMPLATE_DECL                                                         \
  inline RETURN_TYPE* CLASS::Mutable##FUNCTION() {                      \
    return &MEMBER;                                                     \
  }                                                                     \
                                                                        \
  TEMPLATE_DECL                                                         \
  inline const RETURN_TYPE& CLASS::FUNCTION() const {                   \
    return MEMBER;                                                      \
  }

这就是我将如何将它用于包含名为 int_int 的类模板:

IMPLEMENT_ACCESSORS(template<typename T>, int, MyTemplate<T>, Int, int_)

对于非模板类,我不需要template&lt;typename T&gt;,所以我省略了那个宏参数:

IMPLEMENT_ACCESORS(, int, MyClass, Int, int_)

【问题讨论】:

  • 为什么不简单有两个同名的不同宏。少取一论
  • @parapura rajkumar:同样的原因,你不希望两个函数做同样的事情。如果一段代码被重复比维护它变得更难。任何修复都必须应用于每个副本。
  • FWIW 在使用空参数扩展宏时,即使使用-Wall -Wextra -pedantic -ansi,我也没有收到任何关于 gcc 或 g++ 的警告。您收到的确切警告是什么?
  • @parapura:因为宏不可重载,所以只能有一个具有特定名称的宏。
  • SuperElectric, R. Martinho:我编辑了这个问题以反映 C++11 已经正式发布的事实。

标签: c++ macros c++11


【解决方案1】:

当我这样做时,我通常会用注释代替论点。

放置一个将扩展为空字符串的宏。

#define NOARG
...
MY_MACRO(/*Ignore this Param*/ NOARG, bar, baz)

附言。带有或不带有 -std=c++98 标志的 g++ 没有任何警告。

  • g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3
  • g++ (Apple Inc. build 5666) 4.2.1

【讨论】:

  • 其实是一样的。根据 2.2 翻译阶段,在第 3 步中将 cmets 替换为一个空格,在第 4 步中替换宏。
  • 使用您的技巧,由于 MSalters 解释的原因,警告仍然存在(使用 clang -pedantic -std=c++98)。避免警告的更好方法是使用扩展为空的虚拟宏,例如#define NOARG 那么你可以使用MY_MACRO(NOARG, bar, baz)
【解决方案2】:

是的。相关位是 16.3/11

以最外层为界的预处理标记序列 匹配的括号形成类函数的参数列表 宏。列表中的各个参数用逗号分隔 预处理令牌。

不要求单个参数恰好对应一个标记。事实上,以下部分清楚地表明每个参数可以有多个标记:

在被替换之前,每个参数的预处理标记是 完全替换了宏,好像它们形成了其余的 预处理文件

在您的情况下,一个参数恰好对应于零个标记。这不会引起任何矛盾。

[编辑] 这已由 N1566 更改,以使 C++11 与 C99 保持一致。

【讨论】:

  • 但是那部分是在 C++03 和 C++11 之间发生变化还是一直存在?
  • 绝对 c++03 允许(至少由 gcc 实现)空宏参数,我一直使用它们。
  • @eudoxos:这可能是因为 GCC 即使在 C++ 模式下也实现了 C99 功能
  • @MSalters:嗯,不。这两行#define AA(a,b)AA(,)cpp -Werror -Wall -ansi 愉快地处理(根据手册页,这与C90 相同)。
  • @eudoxos GCC 选择将一堆在 C89 和/或 C++98 中未定义但由 C99 定义的行为视为具有其 C99 语义,无论是否明确启用 C99 支持在。 (其中许多在 C99 之前“未定义,但所有实现都以这种方式进行”,这只是编纂实践。)
【解决方案3】:

如果我理解正确,自 C99 和 C++0x(11).
C99 6.10.3/4 说:

...参数的数量(包括那些由 没有预处理标记)应等于参数的数量...

和C++ N3290 16.3/4有同样的说法,而C++03 16.3/10提到:

...任何参数都不包含预处理标记,行为是 未定义。

我认为空参数属于表示由以下组成的参数 上面没有预处理标记
此外,国际标准编程语言 C rev 的基本原理中的 6.10.3。 5.10 说:

C99 的一个新特性:类似函数的宏调用现在也可以 有空参数,也就是说,一个参数可以由 no 预处理令牌。

【讨论】:

  • 我正在寻找空参数列表的用途,但所有网站都只说它们存在。你知道任何例子吗?
  • @Shahbaz 下面是一个例子:#define JOIN(x,y,z) x##y##z,然后使用 JOIN(a,b,c); JOIN(a,b,); JOIN(a,,) 得到abc; ab; a
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-20
  • 1970-01-01
  • 2013-09-04
相关资源
最近更新 更多