SFINAE:使用 'static_cast<void>()' 还是 ', void()'?

9

当对一个任意类型进行SFINAE时,通常需要将表达式的结果转换为void。我见过两种做法;一种是强制转换为void:

(void)(expr)    // or static_cast<void>(expr)

或者,作为另一种选择,使用逗号运算符和void prvalue RHS:
(expr), void()

据我所知,在这两种情况下,expr 都会被评估(在非评估上下文中进行格式检查),并且结果(或结果类型,在非评估上下文中)会被丢弃;即使是一种病态类 T,也无法覆盖 T::operator void()operator,(T, void)。 (参见:为什么使用转换语法时不调用“operator void”?“auto f(params) -> decltype(..., void())”中的“void()”是做什么用的?)。
话虽如此,这两种习惯用法是否等效,或者在任何情况下都应该优先选择其中之一(可能使用非标准编译器)?如果没有,是否有任何理由(例如可理解性)更喜欢其中之一?

我会使用最短和最清晰的符号。如果有任何微妙之处需要使用逗号表达式,我会在特定情况下使用它,并附上解释为什么要这样做的注释。不过,我想不到任何这样微妙的情况。 - Cheers and hth. - Alf
3个回答

2
他们都满足所需的要求:
  • 要求expr作为废弃值表达式有效,且仅限于此。
  • 始终具有类型void(用于尾随返回类型或部分特化
因此,在考虑上述标准时,这两种方法是等效的。请记住,在您的代码中使用更简洁的内容;但无论您选择什么,都应保持一致性。
也可以使用函数式转换,因为当只有一个参数时,它根据定义等同于显式转换符号 - 即:
auto g(auto f) -> decltype(void( f(1, 2, 3) ));

也适用。

1
区别基本上是风格上的。
在某些情况下,由于逗号运算符的低优先级,void()形式可以避免额外的括号。例如,foo + bar, void()完全可以正常工作,但是(void) (foo + bar)(或者函数式转换等效形式)将需要将整个表达式放在括号中。
在其他情况下,使用(void)转换可能更加简洁。例如,为了防止++it1, ++it2, ++it3中的重载逗号,可以使用一个(void)转换- ++it1, (void) ++it2, ++it3,但使用void()将需要写两次:++it1, void(), ++it2, void(), ++it3

0

将其转换为void类型,因为逗号可以被重载。


有一个完整的段落表明OP知道为什么这些模式存在。他正在请求它们之间的比较。 - Quentin
1
逗号运算符不能在其中一个操作数为 void 的情况下进行重载。 - ecatmur

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