Why do switch and if statements behave differently with conversion operators?

  • A+
Category:Languages

Why do switch and if statements behave differently with conversion operators?

struct WrapperA {     explicit operator bool() { return false; }     };  struct WrapperB {     explicit operator int() { return 0; } };  int main() {     WrapperA wrapper_a;     if (wrapper_a) { /** this line compiles **/ }      WrapperB wrapper_b;     switch (wrapper_b) { /** this line does NOT compile **/ } } 

The compilation error is switch quantity is not an integer while in the if statement it is perfectly recognized as a bool. (GCC)

 


The syntax is switch ( condition ) statement with

condition - any expression of integral or enumeration type, or of a class type contextually implicitly convertible to an integral or enumeration type, or a declaration of a single non-array variable of such type with a brace-or-equals initializer.

Taken from cppreference.

This means you can only do a switch case on an integer or enum type. For the compiler to be able implicitly convert Wrapper to integer / enum type you need to remove the explicit keyword :

The explicit specifier specifies that a constructor or conversion function (since C++11) doesn't allow implicit conversions

You can also cast Wrapper to int type.

Edit to adress @acraig5075 remarks :

You must be careful which operator is explicit and which is implicit. If both are implicit the code won't compile because there will be an amibiguity :

struct Wrapper {     operator int() { return 0; }     operator bool() { return true; }     }; 

source_file.cpp: In function ‘int main()’: source_file.cpp:12:14:

error: ambiguous default type conversion from ‘Wrapper’

switch (w) {

^ source_file.cpp:12:14: note: candidate conversion

include ‘Wrapper::operator int()’ and ‘Wrapper::operator bool()’

The only way to remove the ambiguity is to do a cast.

If only one of the operator is explicit, the other one will be chosen for the switch statement :

#include <iostream> struct Wrapper {     explicit operator int() { return 0; }     operator bool() { return true; }     };  int main() {     Wrapper w;     if (w) { /** this line compiles **/std::cout << " if is true " << std::endl; }     switch (w) {          case 0:             std::cout << "case 0" << std::endl;             break;         case 1:             std::cout << "case 1" << std::endl;             break;     }     return 0; } 

Output :

 if is true  case 1 

w has been implicitly converted to 1 (true) (because operator int is explicit) and case 1 is executed.

On the other hand :

struct Wrapper {     operator int() { return 0; }     explicit operator bool() { return true; }     }; 

Ouput :

 if is true  case 0 

w has been implicitly converted to 0 because operator bool is explicit.

In both case, the if statement is true because w is evaluated contextually to a boolean inside the if-statement.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: