在任意类型上执行SFINAE时,通常需要将表达式的结果转换为void
。我已经看到了两种方法;演员无效:
(void)(expr) // or static_cast<void>(expr)
或者,使用带有void prvalue RHS的逗号运算符:
(expr), void()
我的理解是,在两种情况下expr
都被评估(对于格式良好,在非评估的上下文中),结果(或结果类型,在非评估的上下文中)被丢弃;在任何一种情况下,即使是病态类T
也无法覆盖T::operator void()
或operator,(T, void)
。 (参见:Why is "operator void" not invoked with cast syntax?,What does the 'void()' in 'auto f(params) -> decltype(..., void())' do?)。
那就是说,这两个成语是等价的,还是在某种情况下应该优先考虑另一个(可能是非标准的编译器)?如果没有,是否有任何理由(例如可理解性)更喜欢一个而不是另一个?
答案 0 :(得分:2)
他们都符合所需的要求:
expr
作为废弃值表达式有效,仅作为。void
(用于跟踪返回类型或用于partial specializations)因此,当考虑上述标准时,这些方法是等效的。 牢记这一点,我建议您在代码中使用更简洁的内容;但无论你选择什么,都要坚持下去以保持一致 也可以使用函数样式转换,因为当只有一个参数时,它的定义等同于显式转换符号 - 即。
auto g(auto f) -> decltype(void( f(1, 2, 3) ));
也有效。
答案 1 :(得分:1)
差异基本上是文体。
在某些情况下,由于逗号运算符的优先级较低,void()
形式可以避免使用额外的括号。例如,foo + bar, void()
工作正常,但(void) (foo + bar)
(或函数式强制转换等效)将需要对整个表达式进行括号。
在其他情况下,使用(void)
强制转换可能更简洁。例如,为了防止++it1, ++it2, ++it3
中的重载逗号,您可以使用一个(void)
强制转换 - ++it1, (void) ++it2, ++it3
,但要使用void()
则需要编写两次:{{1} }。
答案 2 :(得分:0)
转换为void,因为逗号可以重载。