Using sets in "switch" statement [duplicate] - c++

This question already has answers here:
How do I select a range of values in a switch statement?
(18 answers)
Closed 9 years ago.
Am I able to add sets instead of numbers to "switch" statement? Like:
switch(number)
{
case 1<50: //if number is between 1 and 50
{
blah;
break;
}
case 50<100: //if number is between 50 and 100
{
blah;
break;
}
and so on.

(Edit following comments below, acknowledgement given to user syam)
No. In C++ you can only switch on things that reduce to an integer. You'll need to build a function that computes integral results for 1 < 50 and 50 < 100 etc. and use switch(thatFunction(...)).
Or, if you don't need the follow-though idiom that a switch gives you (by the looks of your example, you don't), just use if, else if, else.
Extract from below comments:
6.4.2-2 [stmt.switch] The condition shall be of integral type, enumeration type, or of a class type for which a single non-explicit conversion function to integral or enumeration type exists [...] the constant-expression shall be a converted constant expression (5.19) of the promoted type of the switch condition

1 < 50 is a boolean expression that gets a compile-time value of true, and thus becomes 1 in an integer context. So you end up with two identical cases in your switch. Compile with high warning level - your compiler will surely complain.

Sadly not. You can use fall-through for a small set of discrete values:
case 1:
case 2:
blah;
break;
but for large ranges the only sensible option is if...else.

For me, this works on my g++ (GCC) 4.7.2 20121109
#include <iostream>
using namespace std;
int main() {
switch(6) {
case 1 ... 5:
cout << "Between 1 and 5" << endl;
break;
case 6 ... 10:
cout << "Between 6 and 10" << endl;
break;
}
}
Thanks for stating in the comments that it's GCC's extenstion

Conditionals are not permitted as case statements, so your option is to use if / else statements.

You can't do that in C++. case switches must be a constant that can be converted to an int.

This is nicely discussed here.
A switch statement is useful when you have to use a single variable across many possible conditions. A switch statement works faster than an if-else block by using a jump table. It requires constant integers when it makes the table. The reason expressions that dont evaluate to a fixed value are not allowed is to save from ambiguity.
case 1+a;
break;
case 5;
break;
Now what if a is 4. That will cause issues. If it doesnt use the jump table it wont be much useful than an if-else block

Related

Switch statement and conditional operators c++

My Q is why to use switch statement and the conditional operator when we have the (if else && else if)
Example 1 :
unsigned short int any_number ;
any_number = ((15>0)? 10 : 5);//using here the conditional operator
if(15>0)//using if & else
any_number=10;
else
any_number=5;
Example 2 :
unsigned short int my_score;
std::cout << "what score you expect you got at the exam";
cin >> my_score;
switch(my_score)
{
case 90:
std::cout<<"awesome keep the good work"; break;
case 80 :
std::cout<<"study harder next time"; break ;
case 20:
std::cout << "quit school"; break;
}
if(my_score==90)
std::cout<<"awesome keep the good work";
else if (my_score==80)
std::cout<<"study harder next time";
else if (my_score==20)
std::cout << "quit school";
other than its costs less lines using swith and conditional operators i dont find them useful at all i like more the (if else) more it gives us more space can any one till me the diffrence if there is one ?
There are many reasons why we need switch statement, it is faster and cleaner(my opinion), but there is another reason: if you switch over an enum variable, and if you forgot to handle some enum values, the compiler can catch it for you.
c++ warning: enumeration value not handled in switch [-Wswitch]
main reason is readability
a long sequence of if elses is sometimes harder to read and maintain than a switch statement.
BTW the performance difference will surely disappear in production code created by a modern compiler.
The ?: construct allows you to do thing not expressable in ifs
cout << (j>42?"a":"b")
for example
Your main concern is code readability and how error-prone it is.
For example, when not used with switch, case and breaks (!), it's probably safer to go for if-else.
In C++ is it better to use switch and case statements or to use if statements?
Personally I find the answers there as great as they are simple.
switch case is faster!
for this point, you can use those two structures to write two functionally equivalent codes, and then compare the compiled assembly code.
details you can refer to this: Efficiency analysis of switch and if else

Incorrect Multiple Cases in Switch not generating compiler error [duplicate]

This question already has answers here:
What does comma operator mean in a switch statement?
(6 answers)
Closed 7 years ago.
I know that this code does not work as "expected". Just looking quickly at this code, we think the return value should be 1, but in the execution it returns returns 3.
// incorrect
variable = 1;
switch (variable)
{
case 1, 2:
return 1;
case 3, 4:
return 2;
default:
return 3;
}
and there are some correct options to do this:
// correct 1
variable = 1;
switch (variable)
{
case 1: case 2:
return 1;
case 3: case 4:
return 2;
default:
return 3;
}
or
// correct 2
switch (variable)
{
case 1:
case 2:
return 1;
case 3:
case 4:
return 2;
default:
return 3;
}
This is partially answered in Multiple Cases in Switch:
I would like to know why the incorrect form does compile without error or even warnings (at least in the Borland C++ compiler).
What does the compiler understand in that code?
Just looking quickly at this code, we think the return value should be 1,
I'd say that an experienced C++ developer would immediately notice that something is wrong and quickly conclude that some other programmer accidentally tried to use the comma operator: ,
but in the execution it returns returns 3.
No, the code must not compile, because the case expression is not constant
And as a matter of fact, it does not compile in any halfway modern compiler. For example, MSVC 2013 says:
stackoverflow.cpp(8) : error C2051: case expression not constant
stackoverflow.cpp(10) : error C2051: case expression not constant
An expression like 1, 2 is an application of the comma operator, and the comma operator implies that the expression is not a compile-time constant.
At least until C++11 came along and relaxed the rules to the effect that adding parentheses, i.e. case (1, 2):, would be allowed to compile. It just would not do what you seem to expect.
This is partially answered in Multiple Cases in Switch:
How so? That other question and the answers are almost exclusively about C#, not about C++.
I would like to know why the incorrect form does compile without error
or event warnings (at least in the Borland C++ compiler).
Because the compiler is too old. Better get a new one.
My guess is that in the first case the compiler evaluates the comma operators to result in the code being executed as follows:
switch(variable)
{
case 2:
return 1;
case 4:
return 2;
default:
return 3;
}
From above, it can be seen why the value 3 is returned for input 1. I suggest you read up about the comma operator. There are some excellent threads on SO related to it.
a, b is a valid expression in both C and C++. It means "Evaluate a, discard it, evaluate b". The value of the expression is b. So your original switch has the following meaning:
variable = 1;
switch(variable)
{
case 2:
return 1;
case 4:
return 2;
default:
return 3;
}
For more on the comma operator, you can read the Wikipedia article.
An expression of the form a, b has a value b. That's how the comma operator works.
Ostensibly then, case 1, 2: is equivalent to case 2:, and so on.
However, a case label must be a constant integral expression , and 1, 2 is not a constant expression since it contains the comma operator (the C++ grammar dictates that a constant expression cannot contain the comma operator). Therefore your compiler should issue an error.
You'll often see case 1: case 2: which, due to the follow-through behaviour of the switch, will allow the statement following that line to be run for both the 1 and 2 cases.
Do some experiment.
#include <stdio.h>
int test(int variable) {
switch (variable)
{
case 1, 2:
return 1;
case 3, 4:
return 2;
default:
return 3;
}
}
int main(void) {
int i;
for (i = 1; i <= 5; i++)
{
printf("%d -> %d\n", i, test(i));
}
return 0;
}
Compiled with Borland C++ 5.5.1 for Win32, the output was
1 -> 3
2 -> 1
3 -> 3
4 -> 2
5 -> 3
It shows that the 1, 2 is interpreted as 2 and 3, 4 is interpreted as 4.
In C or C++, comma expressions have following rules:
Operate from left to right.
Value of comma expression is the value of the last expression.
So the code case 1,2: equals to case 2: due to the fact that comma expression has the value of 2.

coldfusion cfscript, switch/case where case between a range

I've got a problem where I want to do one of three things...
if the value of x is 1-5 (inclusive) do A, if x is between 6-13 (inclusive) do B, and if x is between 14-16 do C.
I figured the switch case would be ok, although I guess I could use a plain IF / ELSE IF, however, as I coded it, I can't help but think there is a more elegant way of stating this USING the switch/case (just in case I encounter a similar need that has more then three options).
here is what I have:
switch ( x ) {
case 1:case 2:case 3:case 4:case 5:
// DO A
break;
case 6:case 7:case 8:case 9:case 10:case 11:case 12:case 13:
// DO B
break;
case 14:case 15:case 16:
// DO C
break;
}
is there a way in the case to specify "between" (inclusive or exclusive)?
thanks
Nope. Switch statement are designed to work with single, constant values. Unless the comparison is such that the value can be modified to conform to that rule, the only options are what you have written already OR using if/else if/else, AFAIK. In most cases, the latter is cleaner than a bunch of hard coded case statements IMO.

Why are C++ switch statements limited to constant expressions?

I wanted to use macro functions in switch statements before I realized the statements need to be constant. Example (does not compile):
#define BAND_FIELD1(B) (10 * B + 1)
...
#define BAND_FIELD7(B) (10 * B + 7)
int B = myField % 10;
switch (myField) {
case BAND_FIELD1(B):
variable1[B] = 123;
break;
case BAND_FIELD7(B):
variable7[B] = 321;
break;
...
}
I rather had to use if .. else:
if (myField == BAND_FIELD1(B)
variable1[B] = 123;
else if (myField == BAND_FIELD7(B)
variable7[B] = 321;
Why are the C++ switch statements limited to constant expressions?
One of the strengths of C++ is its static checking. The switch statement is a static control flow construct, whose power lies in the ability to check (statically) whether all cases have been considered, and in being able to group cases sensibly (e.g. fall through common parts).
If you want to check conditions dynamically, you can already do so with a variety of techniques (if statements, conditional operators, associative arrays, virtual functions, to name a few).
The compiler can generate the fastest possible code for a switch when presented with constants--e.g. jump tables or binary search trees.
When given non-constant values, it can't generate code that's any faster than chained if-else statements. Which you already have at your disposal anyway!
Why are the c++ switch statements limited to constant expressions?
Because the check performed by the switch statements are static. This means that the expressions need to be known at compile time.
In C++11 you can use constexpr (if the expressions are derivated by other constant expressions) in your favor. For example consider this function (that replaces your #define):
inline constexpr int BAND_FIELD1(int B) {
return 10 * B + 1;
}
used in the following simplified version of your code:
constexpr int myField = 0;
constexpr int B = myField % 10;
int variable1 = 0;
switch (myField) {
case BAND_FIELD1(B):
variable1 = 123;
break;
// ...
default: break;
}
As you can see, the above code will easily compile.
My answer would be that the C++ switch is a leftover from the C switch, which is a leftover from antique languages like PL/M.
This case uniqueness is just a chance byproduct of a construct that dates back from the 70's, in my opinion.
It does not guarantee in any way that all cases have been covered, especially given the weak typing of C++ enums.
Considering the piles of assembly code C++ routinely generates behind the scene, arguing that C++ switch is limited to constants for performance reasons seems a bit rich to me.
Many other languages support variables and/or non-numeric expressions in switch statements, and I haven't seen many programmers complain about the possible duplicate case values.
To help answer the question, consider the following (IF it was legal):
int a=15;
int b=16;
int c=15;
int value = a;
switch (value)
{
case a:
// Value is A
break;
case b:
// value is B
break;
case c:
// value is C
break;
default:
// value is unknown
}
We would never execute the code for C, because A would be executed instead. The purpose of switch is that check a value which has unique, testable values. Its a clean if..else if..else..if..else.
Compilers analyze the constant values at compile time to generate optimized lookup tables and decision trees to select a case quickly.
For example, if a table can’t be used, the compiler may generate efficient trinary decision trees using sets of 3 cpu instructions: compare to a value to set cpu flags, branch lower to other cases, branch higher to other cases, or fall through to the equal case.
Remember that C/C++ is concerned with performance.
Maybe a new syntax will be added or compilers will be expanded in the future, but standards advancements try to be incremental and not break code that was already written, or invalidate existing compilers.

switch statement and incrementation operator

I wrote the following code:
int i = 0;
switch(i++)
{
case 0:
cout << 0;
case 1:
cout << 1;
}
cout << "\n" << i;
The output of the code was like this:
01
1
Can anyone please explain the first line of output? Why are 0 and 1 both being printed?
First, the expression i++ (post-increment operator) evaluates to 0 (even though it sets the value of i to 1). So inside the switch, the case 0: branch is selected.
Then, because there is no break after your case 0:, the program continues with executing the code in the case 1: label.
Summing it up, you have: 0 from the first switch branch, 1 from the second branch, and another 1 because that's the final value of i.
Because you need to add a break after each case, which prevents execution of the following statements. E.g.
switch(i++)
{
case 0:
cout<<0;
break;
case 1:
cout<<1;
break;
}
Admittedly, the second break is superfluous but I put it there just for the sake of consistency
you need to put "break;" at the end of each case.
switch is a strange construct. It comes from C, and Java and C# adopted it too, so it is not considered totally "non-OO".
switch on state which changes is a valid OO concept, but often is used for switching based on type.
In particular the compiler usually creates a "jump" table which means it is O(1) what block of code gets called, unlike a nested "if" statement. You may have multiple values (not including default) jump to the same point, thus code blocks "run into" each other unless you explicitly insert a "break" statement.
This is how it was done in C and has been retained for C++.
With regards to the value in the switch, it must be a numeric value but does not have to be a constant. In your case i++ evaluates to 0 but increments i to 1. This is well-defined behaviour and there is no issues with sequence points here.