What If I have function return_num(), where I need return some value, but if I switch inserted value x, and I'm sure, that default will return value 1, if I enter anything else... Is necessary to add another return with value 1 to the end of function?
Compiler does not complain.
int return_num(int x) {
switch (x) {
case 0: return 10;
case 1: return 25;
case 2: return 33;
default: return 1;
}
// <--- necessary return?
}
Since the return type isn't void, it is indeeed necessary to not let the function execute to the end.
However, given that the switch returns in all cases, there is no need to add anything. Anything after the switch would be dead code.
This question already has answers here:
Function with missing return value, behavior at runtime
(4 answers)
Closed 5 years ago.
I was helping a friend with one of his C++ assignments and we found the following code snippet would throw exceptions in MSVC, but when compiling with G++, the exact same code would work fine. The exceptions were return because this function called getValue() wasn't returning anything.
string getValue(int value) {
ostringstream convert;
string rtnValue;
switch (value) {
case 11:
{
rtnValue = "J";
break;
}
case 12:
{
rtnValue = "Q";
break;
}
case 13:
{
rtnValue = "K";
break;
}
case 14:
{
rtnValue = "A";
break;
}
default:
{
//
// if the value is a a number, we assume it is 2..10
//
convert << value; // use a stream to convert the number
rtnValue = convert.str(); // into a string
if (value < 2 || value > 10)
{
rtnValue = "ERROR" + rtnValue + "ERROR";
}
}
return rtnValue;
}
}
This program turns integers into strings. For the numbers 11-14 it uses switch statement (I know this isn't the best implementation but it's an introductory class).
We found that this could easily be solved by adding another return statement at the end.
string getValue(int value) {
ostringstream convert;
string rtnValue;
switch (value) {
case 11:
{
rtnValue = "J";
break;
}
case 12:
{
rtnValue = "Q";
break;
}
case 13:
{
rtnValue = "K";
break;
}
case 14:
{
rtnValue = "A";
break;
}
default:
{
//
// if the value is a a number, we assume it is 2..10
//
convert << value; // use a stream to convert the number
rtnValue = convert.str(); // into a string
if (value < 2 || value > 10)
{
rtnValue = "ERROR" + rtnValue + "ERROR";
}
}
return rtnValue;
}
return rtnValue;
}
And this now fixes it for MSVC (and I assume G++ if I checked).
Why did that fix work? Does MSVC and G++ treat parentheses differently with respect to switch statements?
In the first example, the return rtnValue is in the wrong place, and will only ever work when the default case is hit.
In the second example, you have added the return rtnValue in the correct place (and the other can be safely removed).
As to why it worked on GCC and not on MSVC, I don't know, without the return being in the correct place, it's not valid C++ (not all paths have a return value), so you should have got a compilation error on any C++ compiler.
I would suggest the problem is actually the way the braces {} are being used, and your friend thought that the closing brace of the default case, actually closed the switch statement, but it doesn't.
Also, there is no need to have braces on any of the case statements. Braces CAN be used in this way to introduce scoping (for example, temporary variables for a particular case), but in your example, just leads to confusion.
this is the problem
default:
{
convert << value; // use a stream to convert the number
rtnValue = convert.str(); // into a string
if (value < 2 || value > 10)
{
rtnValue = "ERROR" + rtnValue + "ERROR";
}
}
return rtnValue;
}
your return statement is in the wrong block, i.e , switch block.
what happens is that, when a case is satisfied it breaks out of the switch that is why it didn't return anything (because it is now out of switch statement).
In order to fix it you have to move your return statement to out of the switch statement to the end of the function.
This correction will we equivalent to the second code that you have provided.
But even in the second code remove the inner return statement.
Return value
Your return statement in the first sample applies to the default case only since the execution of the switch block ends with a break statement in every other case.
In a non-default case, you leave the return value of your function uninitialized. MSVC does warn about that while debugging (see https://learn.microsoft.com/en-us/visualstudio/debugger/how-to-use-native-run-time-checks for details) but GCC does not. This problem might be detected during compile time but you cannot rely on that.
The return statement added to the second sample is correct. You can remove the original one which becomes superfluous.
Braces
Notice that the braces inside the switch block are not necessary and introduce confusion here. They would be only useful if you created a local variable just to be used in a single case. Anyway, the braces should be indented more than the braces of the switch block. This part
}
return rtnValue;
}
demonstrates the misleading indentation clearly. The indentation used in the second example is one of the good solutions to this problem.
I'm 99% sure this won't work but that remaining 1% is bothering me
int x;
//is this if statement
if(x == 1, 5, 7)
{
//do something here
}
//equivalent to this if statement
if((x == 1) || (x == 5) || (x == 7))
{
//do something here
}
No it's totally not equivalent.
if(x == 1, 5, 7)
calls the comma operator, which will effectively end up in the last value because of , has the lowest precedence:
if(7)
since unfolding with parenthesis should look like
if(((x == 1), 5), 7)
while
if((x == 1) || (x == 2) || (x == 7))
checks if x equals either 1, 2 or 7.
They are not equal. When you write it like
if(x == 1, 5, 7)
{
//do something here
}
it basically translates into
if(7)
{
//do something here
}
which will always be true in case the number in the condition block is a non-zero number.
Example 1:
int main()
{
int x=10;
if(x==1,5,7)
cout<<"hello"<<endl;
return 0;
}
Here, the output is "hello", because 7 is treated as a true boolean variable.
Example 2:
int main()
{
int x=10;
if(x==1,5,0)
cout<<"hello"<<endl;
return 0;
}
Here, there is no output because 0 is considered as a false boolean variable.
Regarding a faster solution discussed in the comment section of the OP, here's a 'fast' solution:
If you have a large number of constant comparisons to perform, a switch statement is faster than individual if(x == 1) statements as it is compiled to a branch-table (a kind of hashtable directly within program code, giving it O(1) lookup), however it's possible that existing compilers will already optimize if(x==1||x==2||x==3...) to a branch-table too.
bool xIsInSet = false;
switch( x ) {
case 0: case 1: case 2: case 3:
case 4: case 5: case 6: case 7: // add a case for each literal comparison
xIsInSet = true; // no `break` needed, there's only 1 case.
}
if( xIsInSet ) {
// do stuff
}
This can be inlined to a lambda which is invoked immediately to eliminate xIsInSet:
if( [&x]() -> bool {
switch(x) { case 0: case 1: case 2: case 3: return true; }
return false; }()
) {
// do stuff
}
Unfortunately C++11's variadic templates don't let us dynamically add case statements, and hacking it using a preprocessor #define is possible - if you don't mind using a metaprogramming library. A better alternative might be an inline #include of a file generated by your build script. What would be even neater would be a way to somehow #include the standard-output from another program (e.g. if we could do #include '.\generateCasesFor.sh 1 2 5 10 12', alas not yet).
Is there a better (or cleaner) way to write the following code?
if(conditionX)
{
if(condition1)
{
// code X1
}
else if(condition2)
{
// code X2
}
}
else if(conditionY)
{
if(condition1)
{
// code Y1
}
else if(condition2)
{
// code Y2
}
}
I have a few more conditions, but I guess you get the point.
There are four approaches to this problem, none of which is universal:
Leave everything as is - There isn't much code duplication here. If computing condition1 and condition2 is tricky, compute them upfront and store them in bool variables
Make conditionX and conditionY produce a result that lets you unify condition1 and condition2 - This is not always possible, but in some situations you could prepare a variable that unifies the activities taken in the two branches, say, by using a function pointer or a lambda.
Put the processing logic into subclasses with virtual functions to eliminate conditional logic - This is possible only when your initial design missed an opportunity to subclass. Essentially, this approach pushes the decision on conditionX/conditionY into a place where a subclass is created, and then "reuses" that decision later on by calling a proper override of a virtual function in the interface.
Create a numeric combination representing all three conditions, and convert to switch - This trick unifies the conditionals, reducing the nesting.
Here is an example of the last approach:
int caseNumber = ((conditionX?1:0) << 3)
| ((conditionY?1:0) << 2)
| ((condition2?1:0) << 1)
| ((condition1?1:0) << 0);
switch (caseNumber) {
case 0x09:
case 0x0D:
case 0x0F: // code X1
break;
case 0x0A:
case 0x0E: // code X2
break;
case 0x05:
case 0x07: // code Y1
break;
case 0x06: // code Y2
break;
}
If your concern is with clean code in terms of viewing the source, my advice would be to segregate the blocks into their own sections, something like:
if (conditionX) processConditionX();
else if (conditionY) processConditionY();
and so on.
Then, in the sub-functions, you place the "meat":
void processConditionX (void) {
if(condition1) {
// code X1
} else if(condition2) {
// code X2
}
}
You can modify it to pass in and return parameters as necessary and I'd make the conditions and function names a little more descriptive, though I assume they're just examples here.
You can implement a state-machine instead:
#define COMBINATION(a,b,c,d) (((a)<<3)|((b)<<2)|((c)<<1)|((d)<<0))
switch (COMBINATION(conditionX,conditionY,condition1,condition2))
{
case COMBINATION(0,0,0,0): break;
case COMBINATION(0,0,0,1): break;
case COMBINATION(0,0,1,0): break;
case COMBINATION(0,0,1,1): break;
case COMBINATION(0,1,0,0): break;
case COMBINATION(0,1,0,1): CodeY2(); break;
case COMBINATION(0,1,1,0): CodeY1(); break;
case COMBINATION(0,1,1,1): CodeY1(); break;
case COMBINATION(1,0,0,0): break;
case COMBINATION(1,0,0,1): CodeX2(); break;
case COMBINATION(1,0,1,0): CodeX1(); break;
case COMBINATION(1,0,1,1): CodeX1(); break;
case COMBINATION(1,1,0,0): break;
case COMBINATION(1,1,0,1): CodeX2(); break;
case COMBINATION(1,1,1,0): CodeX1(); break;
case COMBINATION(1,1,1,1): CodeX1(); break;
}
This includes only one branch operation, so it is possibly a little more efficient (even though it also includes an additional runtime computation (at the switch line)).
As to being cleaner, I guess it's a matter of perspective, but the template above also gives you a convenient way to detect all unhandled branches within your code.
Please note that if any of the condition variables may have a value other than 1 or 0, then you should:
#define COMBINATION(a,b,c,d) (((a)?8:0)|((b)?4:0)|((c)?2:0)|((d)?1:0))
Update (attributed to #Jonathan Wakely in one of the comments below):
If you're using C++11, then you may replace the COMBINATION macro with a constexpr function:
constexpr int COMBINATION(bool a,bool b,bool c,bool d)
{
return ((int)a<<3) | ((int)b<<2) | ((int)c<<1) | ((int)d<<0);
}
I would provide the decision inside the first if as a parameter to a separated functions which then decides which code to execute, like:
if(conditionX)
{
Method1(Condition Parameters)
}
else if(conditionY)
{
Method1(Condition Parameters)
}
Another way would be to provide all needed info to a decision method (matrix), this method returns an integer which you use in a switch statement to decide which code to execute. In this way you separate the desicion logic which makes it readable and easy to unittest if needed:
DecisionMatrix(conditionX, conditionY, condition1, condition2)
{
// return a value according to the conditions for Example:
// CoditionX + Condition1 => return 1
// CoditionX + Condition2 => return 2
// CoditionY + Condition1 => return 3
// CoditionY + Condition2 => return 4
}
switch(DecisionMatrix)
{
case 1: //run code X1
break;
case 2: //run code X2
break;
case 3: //run code Y1
break;
case 4: //run code Y2
break;
}
The best way here would be to use polymorphism (Only if the chunks of code are huge)
If they are small code snippets, creating classes would obviously be an overkill.
Therefore, if there is similarity in all codes, I'd suggest a seemingly easy but really difficult task.
Try to parametrize them as much as you can.
Create a function that takes those and call them in the conditions
Now the code would be in function blocks and "cleaner"
It is always difficult to create simple things.
if (conditionX) {
method(parameterX);
else if (conditionY) {
method(parameterY);
}
where
void method(ParameterType e) {
if (condition 1) {
// Code in terms of parameter e
} else if (condition2) {
// Code in terms of parameter e
}
}
The condition that you can parametrize should be kept outside.
Hope this helps.
I think this way can be another way for solving your code.
enum ConditionParentType
{
CONDITION_NONE = 0,
CONDITION_X,
CONDITION_Y,
};
enum ConditionChildType
{
CONDITION_0 = 0,
CONDITION_1,
CONDITION_2,
};
class ConditionHandler
{
public:
explicit ConditionHandler(ConditionParentType p_type, ConditionChildType c_type)
: p_type_(p_type), c_type_(c_type) {};
void DoAction()
{
if(child_type == CONDITION_1)
{
}
else if(child_type == CONDITION_2)
{
}
else
{
//error
}
}
private:
const ConditionParentType p_type_;
const ConditionChildType c_type_;
};
int main(int argc, char *argv[])
{
ConditionParentType parent_type = GetParentType();
ConditionChildType child_type = GetChildType();
ConditionHandler handler(parent_type, child_type);
handler.DoAction();
getchar();
return 0;
}
If the combination of conditions means something then I'd write a set simple methods that return boolean values. You would end up with something like:
if (first-condition(conditionX, condition1)) {
// code X1
} else if (first-condition(conditionX, condition2)) {
// code X2
} else if (third-condition(conditionY, condition1)) {
// code Y1
} else if (fourth-condition(conditionY, condition2)) {
// code Y2
}
The names of the methods describe the conditions. Don't worry that the methods are only called once (the compiler will probably in-line them anyway), the important bit it that your code then becomes self documenting.
I'm quite surprised by the other suggested answers, which are mostly wrong if:
The two repeated conditions condition1 or condition2 are complex, in which case DRY comes into play, or
Any of the four conditions have side effects, or
Any of the conditions are slow (for example, find the minimum of a large array, or read a file), or
A boolean short-circuit is needed, as in: if (p == 0) {...} else if (p->foo == 42) {...}.
If none of these hold, as is the case 99.42% of the time, then leave the code as it is. Or, as a minor variation, change it so the nesting (that is, indentation) is only one level, not two.
Otherwise, you will need to use temporary variables as follows
const bool tstX = (conditionX);
const bool tstY = tstX || (conditionY);
const bool tst1 = tstY && (condition1);
const bool tst2 = tstY && !tst1 && (condition2);
the original code doesn't look to bad. Depending on the specific case it may or may not be more readable to do something like:
if(conditionX and condition1) {
// code X1
}
else if(conditionX and condition2) {
// code X2
}
else if(conditionY and condition1) {
// code Y1
}
else if(conditionY and condition2)
// code Y2
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I select a range of values in a switch statement?
I've been getting some errors, and I've been searching for some time now, but I have no idea what is the cause of the errors. (I'm quite new to programming.)
Here are the errors I'm getting:
error: 'Essais' cannot appear in a constant-expression| (line 200)
warning: overflow in implicit constant conversion| (line 202)
I have case and cote:
char AfficherCote (int Essais)
{
char Cote;
switch (Essais)
{
(line200) case Essais<=20:
{
(line 202) Cote='Excellent';
return (Cote);
break;
}
case Essais<=40:
{
Cote='Très bon';
return (Cote);
break;
}
case Essais<=60:
{
Cote='Bon';
return (Cote);
break;
}
case Essais<=80:
{
Cote='Moyen';
return (Cote);
break;
}
case Essais<=100:
{
Cote='Muvais';
return (Cote);
break;
}
case Essais>=100:
{
Cote='Très mauvais';
return (Cote);
}
}
}
switch-case only works with constant values(*) (such as 3 or 'a'), not with ranges (such as <=100). You also must not include the variable name in the case statement. Correct syntax would be as follows:
switch (Essais)
{
case 1:
/* ... */
break;
case 2:
/* ... */
break;
default:
/* ... */
}
If you need range tests, use if instead of switch-case:
if (Essais <= 80)
return "Cote";
else if (Essais <= 100)
return "Muvais";
Also note that you can't use single quotation marks ' for strings. Use double quotation marks " instead, and use variables of type std::string (not char) to store strings.
(*) To be precise, the condition given in the case statements must be a constant expression of integral type, enumeration type, or class type convertible to integer or enumeration type (see §6.4.2/2 of the C++ Standard for details).
That's not how switch blocks work. You would need to do something like this instead:
switch (Essais) {
case 20:
...
case 40:
...
case 60:
...
/* etc, etc */
}
Each case compares the value in the switch statement against a specific constant value. If they are equal, that block is executed. In your code, the compiler is complaining because an expression like Essais<=20 is not a constant that it can evaluate at compile time.
Given what you are trying to do, an if ... else if ... else chain would be more appropriate. switch blocks can only test against specific values and can't handle testing ranges, which is what it appears you are trying to do.