为什么 (void)sizeof(param) 不会“使用” param?

4

我有一个宏定义如下:

#define UNREF_PARAM_1(a)
    do { \
        (void)sizeof(a); \
    } \
    while (0)

为了消除编译器警告。在我正在进行的新项目中,VS2013突然再次抱怨未引用的形式参数。
奇怪的是,如果我只使用 (void)param,它确实可以工作。有人知道为什么使用 (void)sizeof(param)时不起作用吗?

2
sizeof 在编译时被求值。 - Ed S.
1
我通常避免使用这样的宏,因为随着代码随时间的变化,人们会忘记将它们删除。我的偏好是在函数头中注释掉参数的名称,这样可以抑制警告并使其无法在不更新代码的情况下开始使用该参数。 - Adrian McCarthy
我在调试版本中使用这个宏,其中我希望某些函数什么都不做,并且不会收到有关未引用参数的警告。目前,我在(void)sizeof(a);指令之前添加了__pragma(warning(suppress:4100))。 - Chris
1个回答

7
sizeof(param)中,param是所谓的未求值操作数,因此不是odr-used -也就是说,在运行时不需要它。然而,(void)param确实构成了odr-use。使用您代码中的符号表示法进行转换在内部调用static_cast。[expr.static.cast]/6:

任何表达式都可以显式转换为类型cv void,在这种情况下,它变成了一个弃值表达式(Clause 5)。

[p.expr]/10:

在某些上下文中,一个表达式只出现为了它的副作用。这样的表达式称为被弃值的表达式。表达式被评估并且其值被丢弃。[…] lvalue-to-rvalue转换(4.1)仅在表达式是易失性限定类型的lvalue时应用[…]

[basic.def.odr]/2:

除非它是未求值操作数(Clause 5)或其子表达式,否则表达式是可能被评估的。表达式的名称作为可能被评估的表达式出现的变量被odr-used,除非它是一个满足出现在常量表达式中的要求(5.19)且立即应用了lvalue-to-rvalue转换(4.1)的对象。

这个引用的第一部分指定sizeof(a)不是a的odr-use,因为a是未求值操作数。显然,(void)a被可能评估。因为a肯定不允许出现在常量表达式中,也没有声明为volatile,所以不会立即应用lvalue-to-rvalue转换,因此a是odr-used。
1)以下是C++11中x是未求值操作数的表达式列表:
  • typeid(x),其中x不是多态类类型的glvalue
  • sizeof(x)(和sizeof x)
  • noexcept(x)
  • decltype(x)
  • alignof(x)? alignas(x)?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接