转换为 `void` 的真正作用是什么?

What does casting to `void` really do?

(void)x; 这样的常用语句允许抑制关于未使用变量 x 的警告。但是如果我尝试编译以下内容,我会得到一些我不太理解的结果:

int main()
{
    int x;
    (short)x;
    (void)x;
    (int)x;
}

用 g++ 编译它,我收到以下警告:

$ g++ test.cpp -Wall -Wextra -o test
test.cpp: In function ‘int main()’:
test.cpp:4:13: warning: statement has no effect [-Wunused-value]
     (short)x;
             ^
test.cpp:6:11: warning: statement has no effect [-Wunused-value]
     (int)x;
           ^

所以我得出结论,转换为 void 与转换为任何其他类型非常不同,目标类型与 decltype(x) 相同或不同。我对可能的解释的猜测是:

以下哪个更正确?如果 none,那么如何解释编译器警告的差异?

这条语句:

(void)x;

说 "Ignore the value of x." 没有 void 这样的类型 - 它是缺少类型。所以它与此有很大不同:

(int)x;

也就是说 "Treat x as if it were an integer." 当生成的整数被忽略时,您会收到警告(如果已启用)。

当您忽略什么都不是的东西时,GCC 不会将其视为问题 - 并且有充分的理由,因为强制转换为 void 是在 C 和 C++ 中显式忽略变量的惯用方法。

转换为 void 用于抑制编译器警告。 Standard 在 §5.2.9/4 中说,

Any expression can be explicitly converted to type “cv void.” The expression value is discarded.

该标准不强制为未使用的局部变量或函数参数生成警告("diagnostic" 标准语)。同样,它也没有规定如何抑制此类警告。将变量表达式强制转换为 void 以抑制此警告已成为 C 和后来的 C++ 社区中的习语,因为结果不能以任何方式使用(除了 (int)x),所以不太可能只是缺少相应的代码。例如:

(int)x;  // maybe you meant f((int)x);
(void)x; // cannot have intended f((void)x);
(void)x; // but remote possibility: f((void*)x);

就个人而言,我觉得这个约定仍然太晦涩难懂,这就是为什么我更喜欢使用函数模板的原因:

template<typename T>
inline void ignore(const T&) {} // e.g. ignore(x);

然而,忽略函数参数的惯用方法是省略它们的名称(如上所示)。当我需要能够在条件编译代码(例如 assert 中命名函数参数时,我经常使用此函数。我发现例如以下比使用 #ifdef NDEBUG 更清晰:

void rate(bool fantastic)
{
    assert(fantastic);
    ignore(fantastic);
}

可能的用途:

auto it = list_.before_begin();
for (auto& entry : list_)
{
    (void)entry; //suppress warning
    ++it;
}

现在迭代器'it'指向最后一个元素