Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SFINAE: 'static_cast<void>()' or ', void()'?

When performing SFINAE on an arbitrary type, it's often necessary to cast the result of an expression to void. I've seen two ways of doing this; a cast to void:

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

Or, alternatively, using the comma operator with a void prvalue RHS:

(expr), void()

It's my understanding that in both cases expr is evaluated (for well-formedness, in a non-evaluated context) and the result (or result type, in a non-evaluated context) discarded; it is not possible in either case for even a pathological class T to override T::operator void() or operator,(T, void). (See: Why is "operator void" not invoked with cast syntax?, What does the 'void()' in 'auto f(params) -> decltype(..., void())' do?).

That said, are these two idioms equivalent, or are there any circumstances under which one should be preferred to the other (possibly with nonstandard compilers)? If not, are there any reasons (e.g. understandability) to prefer one over the other?

like image 401
ecatmur Avatar asked Mar 03 '15 16:03

ecatmur


2 Answers

They both meet the requirements needed:

  • Require that expr be valid as a discarded-value expression, and only that.
  • Always have type void (for use in trailing return types or for partial specializations)

Thus the methods are equivalent when considering the above criteria. Keeping that in mind, I'd recommend to use whatever is more concise in your code; but whatever you choose, stick to it for consistency.
One can also use a functional style cast, since it is by definition equivalent to the explicit cast notation when there is only one argument - i.e.

auto g(auto f) -> decltype(void( f(1, 2, 3) ));

also works.

like image 182
Columbo Avatar answered Oct 17 '22 04:10

Columbo


The difference is basically stylistic.

In some cases, due to the low precedence of the comma operator, the void() form can avoid an extra pair of parentheses. For instance, foo + bar, void() works just fine, but (void) (foo + bar) (or the functional-style cast equivalent) will require parenthesizing the whole expression.

In other cases, using a (void) cast may be more concise. For example, to protect against overloaded commas in ++it1, ++it2, ++it3, you can use one (void) cast - ++it1, (void) ++it2, ++it3, but to use void() would require writing it twice: ++it1, void(), ++it2, void(), ++it3.

like image 39
T.C. Avatar answered Oct 17 '22 05:10

T.C.