In C/C++ I have scenario where if should be executed on the basis of empty size.
If size of variable a is 0 then string 'add name' should be printed otherwise 'leave it' string should be printed. But I have switch cases for encoding as well for each case there will be different if condition.
switch(encoding)
case utf:
if(a->size-5 == 0)
{
cout<<"add name";
}
else
{
cout<<"leave it";
}
case ansi:
if(a->size-4 == 0)
{
cout<<"add name";
}
else
{
cout<<"leave it";
}
case ansi8:
if(a->size-8 == 0)
{
cout<<"add name";
}
else
{
cout<<"leave it";
}
I want to do it in minimal way. So what is the best way to do that.
I don't fully understand what solution you are expecting, but - same as suggested in a comment - when removing duplication from your code we are left with:
if(a->size-offset == 0)
{
cout<<"add name";
}
else
{
cout<<"leave it";
}
Where offset can be determined via:
int offset = 0;
switch(encoding) {
case utf: offset = 5; break;
case ansi: offset = 4; break;
case asni8: offset = 8; break;
}
Probably a cleaner solution would be to use a polymorphic type such that differences in the encoding are encapsulated in virtual methods, and you can write:
if(a->check_size())
{
cout<<"add name";
}
else
{
cout<<"leave it";
}
I think that ternary operator is the best approach.
switch(encoding) {
case utf:
(a->size - 5 == 0) ? std::cout << "add name" : std::cout << "leave it";
break;
case ansi:
(a->size - 4 == 0) ? std::cout << "add name" : std::cout << "leave it";
break;
case ansi8:
(a->size - 8 == 0) ? std::cout << "add name" : std::cout << "leave it";
break;
}
I'd write your code like this:
//...
//assuming utf, ansi, and ansi8 are enumerated constants
static const int encoding2size[]={ [utf]=5,[ansi]=4,[ansi8]=8 };
//...
if(a->size - encoding2size[encoding] == 0) cout<<"add name";
else cout<<"leave it";
//...
Maybe create a separate function for the if-else part that takes in an offset as input, and call the function with the desired input (desired offset) from each case in the switch case statement? This will at least help avoiding code duplication.
I am having a problem, where I need to declare an object for a class based on user input. The problem is that the scope of the object is stuck in the switch statement, and I was wondering if there was a way to make it public.
//ask the user to choose the class of the first fighter
cout << "Welcome to the fighting arena! Would you like the first competitor to be a FIGHTER <1>, a WIZARD <2>, a ROGUE <3>, or a RANGER <4>?" << endl;
cin >> competitor1;
cout << "And what is the name of the competitor?" << endl;
cin >> name1;
//creates an object in the appropriate class and initializes it
switch (competitor1)
{
case 1:
{
Fighter Battler1(name1);
break;
}
case 2:
{
Wizard Battler1(name1);
break;
}
case 3:
{
Rogue Battler1(name1);
break;
}
case 4:
{
Ranger Battler1(name1);
break;
}
default:
cout << "Sorry please enter a valid number!" <<endl << endl;
break;
}
cout << Battler1.hp //this is undefined because of the scope
Yes everything is written inside the main fuction, I know the probelm is scope and just need a way to get around it.
I wouldn't use a switch case at all here, instead, an array of functors, that each create a different type of fighter and return a pointer to their base, i.e.
template<typename T>
std::unique_ptr<Champion> Create( ) { return std::make_unique<T>( ); }
std::function<std::unique_ptr<Champion>(void)> createFunctions [] = {
Create<Fighter>
,Create<Rogue>
,Create<Wizard>
,Create<Ranger>
};
Usage:
std::cin >> competitor1;
std::unique_ptr<Champion> Battler1 = createFunctions[competitor1];
std::cout << Battler1->hp;
You cannot do it as you described. You will need some kind of polymorphism: an object that will change it's behavior depending on it's type.
The most straightforward way to do it would be to use a variant:
using Battler = std::variant<Fighter, Wizard, Rogue, Ranger>;
auto battler1 = [&]() -> std::optional<Battler> {
switch (competitor1)
{
case 1:
return Fighter{name1};
case 2:
return Wizard{name1};
case 3:
return Rogue{name1};
case 4:
return Ranger{name1};
default:
cout <<"Sorry please enter a valid number!" << endl;
return std::nullopt;
}
}();
// if a valid number has been chose.
if (battler1) {
cout << std::visit([](auto& battler) { return battler.hp; }, *battler1);
}
Note that you need an up to date compiler, or using boost::variant instead. This solution might also not be the most scalable as you'll need to effectively update the Battler alias when adding a new battler type.
Also, you could use polymorphism through pointers and vtables. It require more changes to your program, but might be more appropriate in some cases:
struct Battler {
virtual int getHp() const = 0;
virtual ~Battler() = default;
};
struct Fighter : Battler {
int getHp() const override {
return hp;
}
};
struct Wizard : Battler {
int getHp() const override {
return hp;
}
};
// ... all other classes of Battler
Then, change you switch case accordingly:
std::unique_ptr<Battler> battler1;
switch (competitor1)
{
case 1:
battler1 = std::make_unique<Fighter>(name1);
break;
case 2:
battler1 = std::make_unique<Wizard>(name1);
break;
case 3:
battler1 = std::make_unique<Rogue>(name1);
break;
case 4:
battler1 = std::make_unique<Ranger>(name1);
break;
default:
cout << "Sorry please enter a valid number!" <<endl << endl;
break;
}
// if a valid number has been chose
if (battler1) {
cout << battler1->getHp();
}
If you could make the object (Battler1) global, what datatype would it be? Instance of class Fighter, Wizard, Rogue or Ranger?
The solution to your problem is this: Create a parent class (let's say, Character) from which all the others (Fighter...) will inherit: class Fighter : Character etc. And then, create the objects dynamically:
Character *battler;
switch (...) {
case 1:
battler = new Fighter(name);
break;
case 2:
battler = new Wizard(name);
break;
}
// don't forget to free the memory when not needed anymore
delete battler;
This is a growing source of irritation for me at the moment, when I press the corresponding button for the cases (they're initialized above) they don't actually execute and I'm stuck in the menu.
I'm sure this is ridiculously simple and I'm just not seeing it.
Edit: Added more, upon request
const int POKER = 1;
const int EVAL = 2;
const int EXIT = 3;
const char FIVE_CARD = 'a';
const char TEXAS = 'b';
const char OMAHA = 'c';
const char SEVEN_CARD = 'd';
const char GO_BACK = 'e';
const char MENU[] = "\nPlease choose an option from the following:\n"
"1) Play Poker\n2) Set Evaluation Method\n3) Quit\n: ";
const char POKER_MENU[] = "\nPlease choose your game:\n"
"a) 5 Card Draw\nb) Texas Hold 'Em\nc) Omaha High\n"
"d) 7 Card Stud\ne) Go back\n: ";
int main()
{
int choice = 0;
char poker_choice;
do
{
choice = askForInt(MENU, EXIT, POKER);
switch(choice)
{
case POKER :
do
{
choice = askForChar(POKER_MENU, GO_BACK, FIVE_CARD);
switch(poker_choice)
{
case FIVE_CARD :
std::cout << "Not implemented yet" << std::endl;
break;
case TEXAS :
std::cout << "Not implemented yet" << std::endl;
break;
case OMAHA :
std::cout << "Not implemented yet" << std::endl;
break;
case SEVEN_CARD :
std::cout << "Not implemented yet" << std::endl;
break;
case GO_BACK :
break;
}
}while(poker_choice != GO_BACK);
case EVAL :
std::cout << "Not implemented yet" << std::endl;
break;
case EXIT :
break;
}
}while(choice != EXIT);
choice = askForChar(POKER_MENU, GO_BACK, FIVE_CARD);
should be
poker_choice = askForChar(POKER_MENU, GO_BACK, FIVE_CARD);
Since you mentioned this is inside a method,
There are few things to check here;
Once inside the method, just print poker_choice and see if your the value is getting passed correctly.
Check if all the cases FIVE_CARD, TEXAS are declared as constants of the same data type.
Your error seems to be on this line:
choice = askForChar(POKER_MENU, GO_BACK, FIVE_CARD);
You test poker_choice in your switch but you assign the value to choice.
It should be:
poker_choice = askForChar(POKER_MENU, GO_BACK, FIVE_CARD);
// ^^^^^^
switch(poker_choice)
// ...
I have an assignment to learn how to use boost::variant. I'm trying to create a function that asks the user for a shape type to create. Then create the requested shape and assign it to the variant and return it. I'm using a switch to accomplish this, but I'm getting a runtime error with the default statement.
I also get a warning from the compiler: "warning C4715: 'ShapeVariant' : not all control paths return a value"
How do I just print a string if the user enters an invalid selection?
Thanks!
#include "boost/variant.hpp"
typedef boost::variant<Point,Line,Circle> ShapeType;
ShapeType ShapeVariant()
{
cout << "Please select a Shape Type\n1: Point\n2: Line\n3: Circle\n\nSelection: ";
int choice;
cin >> choice;
switch(choice)
{
case 1: return Point(); break;
case 2: return Line(); break;
case 3: return Circle(); break;
default: cout << "Invalid selection." << endl; break;
}
}
Instead of printing a string from the function, you could instead throw an exception that the caller catches and prints the reason why the exception was thrown.
switch(choice)
{
case 1: return Point(); break;
case 2: return Line(); break;
case 3: return Circle(); break;
default: throw std::runtime_error( "Invalid selection." );
}
In the caller:
try {
auto result = ShapeVariant();
} catch( std::exception const& e ) {
std::cout << e.what() << std::endl;
}
You cannot do this in C++, running such code will result in undefined behaviour in the invalid case. If the selection is really that invalid, throw an exception. You could also look into boost::optional which is designed for cases like this one.
When I try to compile I get this error:
1>------ Build started: Project: snake, Configuration: Debug Win32 ------
1> exercise.cpp
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(13): error C2059: syntax error : '>='
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(16): error C2059: syntax error : '>='
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(19): error C2059: syntax error : '>='
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(22): error C2059: syntax error : '>='
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(25): error C2059: syntax error : '>'
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(28): error C2059: syntax error : '=='
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(34): warning C4065: switch statement contains 'default' but no 'case' labels
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Code:
#include <iostream>
using namespace std;
int main(){
int score;
//Vraag de score
cout << "Score:";
cin >> score;
//Switch
switch(score){
case >= 100:
cout << "a";
break;
case >= 50:
cout << "b";
break;
case >= 25:
cout << "c";
break;
case >= 10:
cout << "d";
break;
case > 0:
cout << "e";
break;
case == 0:
cout << "f";
break;
default:
cout << "BAD VALUE";
break;
}
cout << endl;
return 0;
}
How can I fix this problem? It's a console application, Win32 and my IDE is Windows Enterprise C++ 2010.
I'm learning from Beginning C++ Through Game Programming.
Some compilers support case ranges like case x ... y as an extension to the C++ language.
Example:
#include <iostream>
using namespace std;
int main(){
int score;
//Vraag de score
cout << "Score:";
cin >> score;
//Switch
switch(score){
case 0:
cout << "a";
break;
case 0 ... 9:
cout << "b";
break;
case 11 ... 24:
cout << "c";
break;
case 25 ... 49:
cout << "d";
break;
case 50 ... 100:
cout << "e";
break;
default:
cout << "BAD VALUE";
break;
}
cout << endl;
return 0;
}
GCC 4.9, Clang 3.5.1 and Intel C/C++ Compiler 13.0.1 seem to support it (tried on http://gcc.godbolt.org/). On the other hand, Visual C++ 19 doesn't (tried on http://webcompiler.cloudapp.net/).
In C++ case labels are constant expressions, not expressions in general. You need a chain of if-then-else statements to do what you are trying to do.
Alternatively, you can enumerate the values in the switch. This runs marginally faster (though it does not matter in cases like yours), but it is considerably less readable:
switch(score) {
case 0: cout << "f"; break;
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10: cout << "e"; break;
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
case 24:
case 25: cout << "c"; break;
// ...and so on, you get the idea...
}
You can fix this problem by using a series of if/else if statements. Switch/case cannot be used like this in C++.
It can be done using a std::map with switch:
enum Interval {
One,
Two,
Three,
NotFound };
// [0,10[ is One, [10,30[ is Two, [30,55[ is Three
std::map<int,Interval> imap {
{ { 0, One },
{ 10, Two },
{ 30, Three },
{ 55, NotFound } };
Interval ivalue = NotFound;
auto f = imap.lower_bound( value );
if( f != imap.end() ) ivalue = f->second;
switch( ivalue ) {
case One : ...
case Two : ...
case Three : ...
default: ...
}
Switch-case is not a great option for testing ranges. The best option is to use several if :
if (score<0) cout << "BAD VALUE";
if (score == 0) cout << "f";
if (score>0 && score<10) cout << "e";
if (score>=10 && score <25) cout << "d";
if (score>=25 && score <50) cout << "c";
if (score>=50 && score <100) cout << "b";
If running time is an issue, the following solution is faster :
if (score == 0) cout << "f";
else if (score<10) cout << "e";
else if (score <25) cout << "d";
else if (score <50) cout << "c";
else if (score <100) cout << "b";
else if (score>=100) cout << "a";
else cout << "BAD VALUE";
There's a GCC extension that does exactly what you want.
In C++ a switch statement can only match constant integer values:
switch (i)
{
case 1:
//... stuff
break;
case 2:
//... stuff
break;
default:
//... stuff
}
The standard does not allow for this:
6.4.2 The switch statement [stmt.switch]
[...] Any statement within the switch statement can be labeled with one or more case labels as follows:
case constant-expression :
where the constant-expression shall be an integral constant expression (5.19).
In other words, you can only use case-values that expand into a single, integral, "hard" compile time constant (e.g. case 5+6:, enum {X = 3}; ... case X*X:).
The way around this is to use if-statements. E.g., to replace
switch (x)
case 0..100:
you'd instead
if (x>=0 && x<=100)
.
std::map::upper_bound + C++11 lambdas
https://stackoverflow.com/a/35460297/895245 mentioned lower_bound, but we can also get rid of the enum there with lambdas (or inheritance if you don't have it).
#include <functional>
#include <iostream>
#include <map>
int main() {
std::string ret;
const std::map<int,std::function<void()>> m{
{0, [&](){ ret = "too small"; }},
{2, [&](){ ret = "[0,2)"; }},
{5, [&](){ ret = "[2,5)"; }},
{7, [&](){ ret = "[5,7)"; }},
};
const auto end = m.end();
for (auto i = -1; i < 8; ++i) {
auto it = m.upper_bound(i);
if (it == end) {
ret = "too large";
} else {
it->second();
}
std::cout << i << " " << ret << std::endl;
}
}
Output:
-1 too small
0 [0,2)
1 [0,2)
2 [2,5)
3 [2,5)
4 [2,5)
5 [5,7)
6 [5,7)
7 too large
Usage inside methods with static
To use this pattern efficiently inside classes, initialize the lambda map statically, or else you pay n log(n) every time to build it from scratch.
Here we can get away with the {} initialization of a static method variable: Static variables in class methods , but we could also use the methods described at: static constructors in C++? I need to initialize private static objects
It was necessary to transform the lambda context capture [&] into an argument, or that would have been undefined: const static auto lambda used with capture by reference
Example that produces the same output as above:
#include <functional>
#include <iostream>
#include <map>
#include <string>
class RangeSwitch {
public:
void method(int x, std::string &ret) {
static const std::map<int,std::function<void(std::string&)>> m{
{0, [](std::string &ret){ ret = "too small"; }},
{2, [](std::string &ret){ ret = "[0,2)"; }},
{5, [](std::string &ret){ ret = "[2,5)"; }},
{7, [](std::string &ret){ ret = "[5,7)"; }},
};
static const auto end = m.end();
auto it = m.upper_bound(x);
if (it == end) {
ret = "too large";
} else {
it->second(ret);
}
}
};
int main() {
RangeSwitch rangeSwitch;
std::string ret;
for (auto i = -1; i < 8; ++i) {
rangeSwitch.method(i, ret);
std::cout << i << " " << ret << std::endl;
}
}
That's simply not how switch works. It only takes single values. You'll have to use if-elseif blocks
I had the same problem with a score based problem and while the " if/elseif "statements were good to use, for intervals i found that the best option (for me at least because i like how it looks and it's easier for me as a beginner to see my mistakes) is " 1 ... 10 ". but don't forget to use a space between the number and the dots or the program will think that your interval is a number and u will get an error "2 many decimal dots...". Hope it helps.
int score;
int main()
{
cout<<"Enter score"<<endl;
cin>>score;
switch(score){
case 100:
cout<<"Your score is Perfect"<<endl;
break;
case 90 ... 99:
cout<<"You got A"<<endl;
break;
case 80 ... 89:
cout<<"You got B"<<endl;
break;
case 70 ... 79:
cout<<"You got C"<<endl;
break;
case 60 ... 69:
cout<<"You got D"<<endl;
break;
case 50 ... 59:
cout<<"You got E"<<endl;
break;
case 0 ... 49:
cout<<"You got F"<<endl;}
}
Switch case statements are a substitute for long if statements that compare a variable to several "integral" values ("integral" values are simply values that can be expressed as an integer, such as the value of a char). The condition of a switch statement is a value. The case says that if it has the value of whatever is after that case then do whatever follows the colon. The break is used to break out of the case statements.
Therefore, you cannot use such conditional statements in case.
The selective structure: switch
This is what worked for me. dividing the mark by 10 and then setting case 10 and 9 to display an "A"(this will display a "A" for any value between 90-100. Then case 8 to display "B", then case 7 will display a "C" for the values from 70-79 and so on.
#include <iostream>
using namespace std;
main ()
{
int mark;
cout << "enter your mark: ";
cin >> mark;
switch (mark/10)
{
case 10: case 9: cout << "A"; break;
case 8: cout << "B"; break;
case 7: cout << "C"; break;
case 6: cout << "D"; break;
case 5: cout << "PASS"; break;
default: cout << "FAIL"; break;
}
}
You can do the following:
//summarize the range to one value
If score < 0
score = -1
switch(score){
case 1:
//...
break;
case 2:
//...
break;
case -1: //complete neg. range
//...
break;
//...
}
Something like this?
case 'A'..'Z' where a not in ['I','L','O']:
Unfortunately no compiler I know of implements that particular extension, though GCC has can do ranges as other answers pointed out. For portability you can cut and paste this DWTFYW licensed snippet. If you're using a custom enum you might resort to code generation to make something similar.
#define CASE_NUMBER \
case'0':case'1':case'2':case'3':case'4':\
case'5':case'6':case'7':case'8':case'9'
#define CASE_ALPHA_LOWER \
case'a':case'b':case'c':case'd':\
case'e':case'f':case'g':case'h':\
case'i':case'j':case'k':case'l':\
case'm':case'n':case'o':case'p':\
case'q':case'r':case's':case't':\
case'u':case'v':case'w':case'x':\
case'y':case'z'
#define CASE_ALPHA_UPPER \
case'A':case'B':case'C':case'D':\
case'E':case'F':case'G':case'H':\
case'I':case'J':case'K':case'L':\
case'M':case'N':case'O':case'P':\
case'Q':case'R':case'S':case'T':\
case'U':case'V':case'W':case'X':\
case'Y':case'Z'
#define CASE_ALPHA CASE_ALPHA_UPPER:CASE_ALPHA_LOWER
#define CASE_ALPHANUM CASE_ALPHA:CASE_NUMBER
If you access to GHCI such as the online version at https://ghc.io/ you might just generate what you need and paste that into a header e.g.
foldl (++) "" ["case" ++ show x ++ ":" | x <- ['A'..'Z'], not $ x `elem` ['I','L','O']]
Here's a way which I hope is expressive and simple to follow.
You may be surprised by how far gcc/clang etc can optimise the code it generates. I would expect it to be at least as efficient as a switch/case.
#include <iostream>
template<class Value>
struct switcher
{
constexpr switcher(Value const& value) : value_(value) {}
constexpr switcher(Value const& value, bool enabled) : value_(value), enabled(enabled) {}
template<class From, class To, class F>
constexpr auto in_range(From&& from, To&& to, F&& f)
{
if (enabled and (from <= value_ and value_ <= to))
{
f();
return switcher(value_, false);
}
else {
return *this;
}
};
template<class F>
constexpr auto otherwise(F&& f)
{
if (enabled)
f();
}
Value const& value_;
const bool enabled = true;
};
template<class Value>
constexpr auto decision(Value const& value)
{
return switcher<Value>(value);
}
void test(int x)
{
decision(x)
.in_range(0, 10, [&] { std::cout << x << " maps to option A\n"; })
.in_range(11, 20, [&] { std::cout << x << " maps to option B\n"; })
.otherwise([&] { std::cout << x << " is not covered\n"; });
}
int main(int argc, char **argv) {
test(5);
test(14);
test(22);
}
A potentially useful insight is that switch accepts an expression, so you can fold multiple input values down to one switch case. It's a big ugly, but for consideration:
switch (score / 10)
{
case 10:
cout << "a";
break;
case 9: case 8: case 7: case 6: case 5:
cout << "b";
break;
case 4: case 3:
cout << "c";
break;
case 2:
if (score >= 25)
{
cout << "c";
break;
}
// else fall through...
case 1:
cout << "d";
break;
case 0:
cout << (score > 0 ? "e" : "f");
break;
default:
cout << "BAD VALUE";
break;
}
Of course, you could have divided by 5 and had case 4: (for 20-24) vs case 5: (25-29) rather than an if inside case 2:, but /10 is arguably more intuitive.
I know this is an old questiion, but since switch statements are in fact wrappers around labels, I find goto may be of (good) use here.
int value = 40;
if (value < 10) {
std::cout << "value < 10" << std::endl;
goto end;
}
if (value < 50) {
std::cout << "value < 50" << std::endl;
goto end;
}
if (value > 30) {
std::cout << "value > 30" << std::endl;
goto end;
}
end:
// resume
This way, you can omit all the elses and keep it compact.
You ought to be careful when using goto though (in general).