43

While playing with this answer by user GMan I crafted the following snippet (compiled with Visual C++ 9):

 class Class {
 public:
     operator void() {}
 };

 Class object;
 static_cast<void>( object );
 (void)object;
 object.operator void();

after stepping over with the debugger I found out that casting to void doesn't invoke Class::operator void(), only the third invokation (with explicitly invoking the operator) actually invokes the operator, the two casts just do nothing.

Why is the operator void not invoked with the cast syntax?

Community
  • 1
  • 1
sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • 5
    I love how you always ask weird but interesting questions ;) Here is my +1. – ereOn Oct 27 '10 at 08:34
  • What code would you expect to be executed *without* the cast? Actually none... why should casting change this? – Eiko Oct 27 '10 at 08:36
  • 3
    @Eiko: If that was `operator int()` and I wrote `(int)object;` then `operator int()` would be invoked. Turns out this isn't the case with `operator void()`, so I asked this question. – sharptooth Oct 27 '10 at 08:52
  • fwiw, this is called all 3 times when compiled with llvm-gcc 4.2 (apple) – justin Oct 27 '10 at 09:00
  • Well, not with VS C++, but with gcc here, and it gets called three times - checked with some text dumping from the operator void() implementation. Do you have actually code in that method? Maybe it's the compiler optimizing it away. – Eiko Oct 27 '10 at 09:01
  • 3
    For what it's worth, Comeau gives the following warning: "Class::operator void()" will not be called for implicit or explicit conversions". – Luc Touraille Oct 27 '10 at 09:04
  • 3
    and gcc warns: `conversion to void will never use a type conversion operator` – justin Oct 27 '10 at 09:12
  • @Eiko: I added a message box into the operator implementaton - it only shows once, so the operator is only called once. – sharptooth Oct 27 '10 at 09:16

1 Answers1

32

The technical reason why is found in §12.3.2:

A conversion function is never used to convert a (possibly cv-qualified) object to the (possibly cv-qualified) same object type (or a reference to it), to a (possibly cv-qualified) base class of that type (or a reference to it), or to (possibly cv-qualified) void.

The rationale is (likely) to allow §5.2.9/4 to work:

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

(void)expr to suppose to do nothing for the resulting value of any expression, but if it called your conversion operator it wouldn't be discarding anything. So they ban the use of operator void in conversions.


Why not make it ill-formed to have the conversion-type-id be void? Who knows, but keep in mind it's not totally useless:

struct foo
{
    operator void()
    {
        std::cout << "huh?" << std::endl;
    }

};

typedef void (foo::*void_function)();

foo f;
void_function func = &foo::operator void;

(f.*func)(); // prints "huh"
f.operator void(); // also does (which you knew)

It is still technically potentially useful for something, so maybe that's rationale enough not to make it ill-formed.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • 6
    *"Why not make it ill-formed to have the conversion-type-id be `void`?"* Maybe because that `void` might be hidden behind a typedef or template parameter? – dyp Mar 03 '15 at 20:20
  • @dyp, and that's the problem with being *not* _ill-formed_: unexpected behaviour: you expect the conversion operator to convert, but this one won't ever do that. Make it _ill-formed_ would help the developer of supposed template library to catch bugs early on. But, at least nowadays compilers issue the warning for this case. – GreenScape Oct 25 '18 at 10:24
  • @GreenScape There are use cases where you don't care that it won't be called, and with `ill-formed`, you have to generate special cases. Just like `f(future.get())` for `future`. – dyp Oct 26 '18 at 15:06
  • Moreover, the standard conversion to `void` should outcompete any user-defined conversion for the purpose. – Davis Herring Jul 03 '20 at 20:53