0

i am new to C++ and currently learning switch statements, but i don't know why does my compiler throws an error or warning (in case of booleans) when i use boolean, float, & string ?

How can i solve the problem ? or why does it occur

ADMI
  • 75
  • 1
  • 10
  • `switch` is fairly primitive and is largely based on the C version of same. – tadman May 06 '21 at 17:21
  • This is basically how `switch` is implemented in the backend. You can only compare int or char. – Talal02 May 06 '21 at 17:24
  • 2
    There really isn't any clearer answer for this than "the language chooses not to allow this". `float`s wouldn't make sense in any language though, since floating point is rarely exact, and direct equality statements with `float`s are generally a bad idea. Otherwise, the other part of this question with strings has been asked before several times as duplicates (see also: [Evaluate a string with a switch in C++](https://stackoverflow.com/q/16388510/1678770), [Can't expression in switch statement be string?](https://stackoverflow.com/q/65995516/1678770), etc) – Human-Compiler May 06 '21 at 17:31
  • The superficial answer is that `switch` requires an integer type. (not just `int` or `char`; any integer type is okay) – Pete Becker May 06 '21 at 17:33
  • Many implementations of the `switch` statement involve *jump tables*. These are arrays of branch or jump instructions. Like an array, an index of 5.3 or "house" don't make sense. – Thomas Matthews May 06 '21 at 17:35
  • 1
    @ThomasMatthews Although jump-tables are _one possible implementation_ of switch statements, this doesn't appear as common as I would have thought (at least, from my experience playing around with compiler explorer). This seems to mostly happen for _large_ dense ranges. Otherwise for small dense ranges, or for sparse ranges, often the assembly generates something similar to a binary search – Human-Compiler May 06 '21 at 17:36
  • @Human-Compiler Let me clarify. Restricting index types to integers allows for more efficient translation of the `switch` into a jump table. If the case values are not contiguous, another table lookup *may* be required. Two table lookups are still more efficient than comparing strings (for cases). – Thomas Matthews May 06 '21 at 17:44
  • Also, some processors have single instructions to use jump tables. For example, with the ARM processor, you load the PC register using array index techniques (table start + index * size of jump instruction). Loading the PC (program counter) register is the same as a branch instruction. – Thomas Matthews May 06 '21 at 17:46

2 Answers2

2

In days of old and sometimes today, switch statements were translated into arrays of branch or jump statements, preferably contiguous.

As with arrays, indices of 8.9, "frog", and "false" don't make sense.

The C and C++ languages are designed for efficiency when compiled. An array of jump instructions is much more efficient than having to do an "if-else-if" ladder, which is required for other index types (such as floating point and text or string).

For those pedantic readers:
Using integers as case values allows for better optimization (implementation) of the decision structure. Contiguous (consecutive) case values allow for better optimization or implementation. An optimal decision structure is an array of jump, branch instructions or pointers to functions.

For example, an optimum implementation would be:
destination_address = switch_table[case_value]; Many processors can implement this with a single instruction.

Other languages may implement a table of <case_value, destination_address>. One issue with floating point case values is that comparing for equality with floating point is difficult because not all numbers can be represented exactly by floating point. For example if you have case 3.14: and your index is 3.14159, is the case activated?

For string or text case-values, enough characters must be compared to determine equality. For example, "hyperbolic" and "hyperthreading" need to go through 5 iterations to determine equality. Hashing could be used, but there may be more execution with the hashing function than there are letters to compare.

So, to allow compact and efficient implementations of switch statements, the authors of the C and C++ language decided to restrict the case values to integers. Other forms, like strings, will require an if-else-if ladder, table search or dictionary (map).

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
  • If you want an efficient `switch` statement, arrange the `case` statements so that they are contiguous values and in increasing order. – Thomas Matthews May 06 '21 at 17:40
  • I am tempted to vote this down. `switch` statements are not limited to consecutive integers or even integers that are compact in that they fit into an interval with few missing integers. They can be so widely scattered as to be unsuitable for array dispatch. Compilers are free to implement them as some form of array dispatch, binary lookup, serial testing, hybrids, or other means. Binary lookup could work just as easily for floating-point values as it does for integers. So this answer does not answer the question. – Eric Postpischil May 06 '21 at 23:25
  • So, I should remove the word *preferably*, because that seems to imply all cases (or am I wrong about *preferably*)? – Thomas Matthews May 06 '21 at 23:34
  • Regardless of preferably, was it ever true that `switch` statements were only translated into some form of jump array? If a programmer wrote cases including −20000 and +20000, did the compiler generate 40,001 array entries or fail to compile? Can you document this? Was it still true by the time the C standard was made? If not, what was the rationale then? – Eric Postpischil May 06 '21 at 23:37
  • I'll have to dig up my smaller 8-bit and 16-bit machines (including embedded systems), run those compilers in order to get you the proof you want. Again, I'm not stating that the jump tables are **always** used, but they are an optimal implementation. The C and C++ languages are partly designed on emitting efficient machine language (assembly instructions). Other languages are developed on boosting development productivity (not necessarily efficient implementation). Again, the rationale is based upon efficient implementations. – Thomas Matthews May 06 '21 at 23:54
  • Let's use a table of , where case-value is a hard coded text, a.k.a. C-String. The destination address from an integer case-value array can performed by one instruction or a small amount. A lookup where the case-value is text, requires enough iterations to determine equality or inequality. This is one or more iterations of comparisons. More instructions than using an integral case-value. A floating point case-value is affected by the definition of equality for floating point (and the specified precision). – Thomas Matthews May 07 '21 at 00:00
  • You can easily write sample C++ code to demonstrate the efficiency of an array of function pointers versus other decision / dispatch structures. Try it out. IMHO, the array lookup using integral case-values will be the most efficient. You can even use a table of integral case-values, which will still be more efficient than string or floating point case-value types. – Thomas Matthews May 07 '21 at 00:03
0

First, you can use boolean in a switch statement:

int main(int argc, char** argv) {
    bool b = argc > 1;
    switch (b) {
    case true:
        break;
    case false:
        break;
    }
}

As commented above, the float's are not suitable for equality test.

And since you asked "How can i solve the problem ?", for the string I would suggest an unordered map:

std::unordered_map<std::string, int> m = { {"abc", 1}, {"qwe", 2} };
switch(m["foo"]) {
case m["abc"]:
...
}
Vlad Feinstein
  • 10,960
  • 1
  • 12
  • 27