Say we have the following if-statement:
if (arg.compare("abc") == 0)
{
...
}
If I want to convert it to have a switch form, is the following correct?
switch (arg)
{
case "arg.compare("abc") == 0: cout<<"statements the same";
break;
}
Thanks.
If ever the following switch statement was possible:
switch (arg)
{
case arg.compare("abc1") == 0: cout << "statements the same1";
break;
case arg.compare("abc2") == 0: cout << "statements the same2";
break;
}
It would be totally equal to the following if statement (do you want a break statement?):
if(arg.compare("abc1") == 0) cout << "statements the same1";
// no break is needed
else if(arg.compare("abc2") == 0) cout << "statements the same2";
// no break is needed
Which is really equal to:
if(arg.compare("abc1") == 0)
{
cout << "statements the same1";
}
else if(arg.compare("abc2") == 0)
{
cout << "statements the same2";
}
And it is how if-else statement works exactly the way that you wanted, because it will not check for the next conditions if one of them is true.
If the set of strings is statically known to you (at development time, e.g. because it is a set of known keywords or identifiers) you might want to use a perfect hash generator like gperf
If coding in C++11 you could also make a map of anonymous functions:
std::map<std::string, std::function<void(const std::string&)>
funmap = {
{ "abc", [&](const std::string& name)
{ std::cout << name; } },
{ "cde", [&](const std::string& name)
{ do_something_with(name); } },
};
later you would do something like
auto it = funmap.find(somestring);
if (it != funmap.end()) it->second(somestring);
Related
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'm starting to learn C++, and something useful from my main language Lua, is the ability to say:
print(true/false and 1 or 0)
1 or 0 being anything but it seems in c++ it doesnt work the same way?
What I tried for C++ was
cout << (score == 0) and "Valid";
But only a true if check seems to work
if (score == 0) {
cout << "Valid";
} else {
cout << "A";
}
std::cout << ((score == 0) ? "Valid" : "A");
The << in your code isn't simply a syntax, it's an operator:
std::basic_ostream<CharT,Traits>::operator<<
Your attempt will not produce any compilation errors (assuming you have using namespace std;):
cout << (score == 0) and "Valid";
// ^^ T/F ^^ ^^ T ^^
Apply some boolean algebra and that's equivalent to:
cout << true; // if score is 0
cout << false; // if score is not 0
That's certainly not what you are trying to acheive.
Are there ways to do if statements inside a cout line?
if (score == 0)
cout << "Valid";
else
cout << "A";
You can do that using the conditional operator ?:
cout << (score == 0 ? "Valid" : "A");
But this approach is not guaranteed to work always. For example:
cout << (condition ? "String" : 1234);
Reason: Why in conditional operator (?:), second and third operands must have the same type?
Rearranging it like this will work:
condition ? cout << "String" : cout << 1234;
Now, talking about your Lua style:
print(true/false and 1 or 0)
I don't know Lua but that looks like a function. If you are looking for some template like that, try this:
template <typename T, typename U>
void conditionalPrint(const bool& condition, const T& arg1, const U& arg2)
{
condition ? cout << arg1 : cout << arg2;
}
You can use it like this:
conditionalPrint(score == 0, "Valid", "A");
conditionalPrint(someCondition, "String", 1234);
Of course, I'm not going to explain how that works because you're new to C++. I would still recommend the if-else way of doing it. Readability of your code is very important:
if (condition)
{
cout << "true block";
}
else
{
cout << "false block";
}
"Lot can be learned by comparing two lanugages and try to see if what can be done in one can also be done in the other, but usually what is idiomatic in one can be crap in the other. Anyhow, I had my fun with exploring the issue, but imho the conclusion is as important as the rest of the answer" - idclev
I'm currently trying to make a little recipe app. I have made a string array with 10 strings and 10 bools. For example, when I type Cinnemon I want to make the _Cinnemon true. How do I do that?
Also, is this written correctly, or could I make it better? I'm quite new to programming.
Lastly, how can I fix it so it doesn't have anything to say whether it's small letters or big?
Here's the code:
std::cout << "Welcome, type your ingredients " << std::endl;
std::string ingredients[10]{"Cinnemon", "Milk", "Eggs", "Butter", "Tomatoes", "Salt", "Backing Soda", "Suggar", "Chicken", "Honny"};
bool _cinnemon, _milk, _eggs, _butter, _tomatoes, _salt, _backingSoda, _Suggar, _chicken, _honny;
std::string ingredient;
int i = -1;
while (i = -1) {
std::cin >> ingredient;
i++;
while (i < 9)
{
if (ingredient == ingredients[i]){
std::cout << "Type another if you have any more igredients else type Exit" << std::endl;
i++;
} if (ingredient == "Exit" || "exit"){
return 0;
} else{
i++;
}
}
}
Try to map your hard-coded strings into booleans. So you can change them easily.
map<string, bool> m;
m["blah"] = false; // Initialize to false
// Later, you can change it by
m["blah"] = true;
// To look up a value, simply do
if(m.count("blah") && m["blah"]) {
// "blah" is true and do whatever you want to do here
}
As for string comparison ignoring the case, you can write your own function to do that, for example
#include <cctype> // This is where tolower() is defined
bool stringCmpIgnoreCase(string a, string b) {
if(a.length() != b.length())
return false;
for(int i = 0; i < a.length(); i++)
if(tolower(a[i]) != tolower(b[i]))
return false;
return true;
}
I understand that you are learning, so I'll avoid advanced datastructures such as maps and sets, which would be used for a real life application.
My proposed solution just uses an array of boolean. For every indegrients which string is found, I set the boolean flag at the same index. Here is how it works:
std::cout << "Welcome, type your ingredients " << std::endl;
const size_t maxind = 10; // avoid hard coded size !
std::string ingredients[maxind]{"Cinnemon", "Milk", "Eggs", "Butter", "Tomatoes", "Salt", "Backing Soda", "Suggar", "Chicken", "Honny"};
bool hasindegrient[maxind]{}; // make a table to know which one is present
std::string ingredient;
bool stopit = false; // exit requested ?
while (! stopit) {
std::cin >> ingredient;
int i;
for (i=0; i<maxind; i++)
if (ingredient == ingredients[i]){
hasindegrient[i] = true; // <================ set flag of indegrient
break;
}
if (i==maxind) { // here we didn't find it !
if (ingredient == "Exit" || ingredient == "exit")
stopit = true;
else
std::cout << "Indegrient not found !" << std::endl;
if (!stopit)
std::cout << "Type another if you have any more igredients else type Exit" << std::endl;
}
}
for (int i=0; i<10; i++) // display the indegrient list
if (hasindegrient[i])
cout << ingredients[i]<< " ";
cout << endl;
With this approach, each boolean is anonymous: each hasindegrient[i] is either true or false, but has no name. So on its own it doesn't mean anything. But in this programme, if hasindegrient[i] is true, it means that indegrients[i] is in the receipe.
If you want to add some logic where your code interprets the content of the receipe, you could add at the begin an enum that gives a logical name to each index:
enum {IDG_Cinnemon, IDG_Milk, IDG_Eggs, IDG_Butter, IDG_Tomatoes, IDG_Salt, IDG_Backing_Soda, IDG_Suggar, IDG_Chicken, IDG_Honny };
You can understand each element of this enumeration as a constant. As you see, I've followed the same order than in the table of strings. This allows then the writing of code such as:
if (hasindegrient[IDG_Butter]) {
std::cout << "Take care of your cholesterol" << std::endl;
}
Important remarks:
I think you should know some problems of your original code:
while (i = -1) will loop forever, whatever the value of i is. = is the assignement operator (i.e. -1 is copied to i and the value of i is evaluated in condition). This is the most common errors when starting with C/C++: you certainly meant while (i==-1) which is a comparison.
ingredient == "Exit" || "exit" is a valid syntax. But this condition is always true. It does in no way mean "indegrient is either Exit or exit" . For this you'd write ingredient == "Exit" || ingredient =="exit"
your loop structure will not succeed in the search. Especially if the entering of the indegrients doesn't follow the predefined list...
There are different approaches for this task. For example you could use a bool array and an enumeration with names of ingredients that would be used as indices of the array.
You could use std::bitset or std::vector<bool>
You could use an array of pairs std::pair<std::string, bool>.
Also you can use std::map.
Here is a demonstrative program
#include <iostream>
#include <map>
#include <string>
int main()
{
std::map<std::string, bool> ingredients =
{
{ "Cinnemon", false }, { "Milk", false }, { "Eggs",false },
{ "Butter", false }, { "Tomatoes", false }, { "Salt", false },
{ "Backing Soda", false }, { "Suggar", false }, { "Chicken", false },
{ "Honny", false }
};
std::cout << "Welcome, type your ingredients\n" << std::endl;
std::string ingredient;
bool selected = false;
while ( std::getline(std::cin, ingredient ) )
{
if ( ingredient == "Exit" | ingredient == "exit" ) break;
if ( selected = ( ingredients.count( ingredient ) != 0 ) )
{
ingredients[ingredient] = true;
}
else
{
std::cout << "Invalid ingredient." << std::endl;
}
std::cout << "Type another if you have any more igredients else type Exit" << std::endl;
}
if ( selected )
{
std::cout << "You selected ingredients:" << std::endl;
for ( const auto &p : ingredients )
{
if ( p.second ) std::cout << p.first << std::endl;
}
}
return 0;
}
Take into account that you have to use function std::getline instead of operator >> because some ingredient names consist from several words.
Also you should make case insensitive search.
char x;
bool tf;
void IsNumber(char x)
{
switch (x)
{
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '0':
bool tf(true);
break;
default:
bool tf(false);
break;
}
}
int main(int argc, const char * argv[])
{
using namespace std;
cout << "Test if a character is a number: " << endl;
char x;
cin >> x;
IsNumber((char) x);
if (bool tf = true)
cout << "True" << endl;
if (bool tf = false)
cout << "False" << endl;
return 0;
}
I am getting an error after the default: saying I can't redefine the variable. Also, it says, at the bottom, that I the variable tf isn't a variable. I am really new to C++, I only know python can someone help me out?
New code giving me an error:
#include <iostream>
bool tf;
tf = true;
bool IsNumber(char x)
{
switch (x)
{
case '1':
You're trying to declare two variables with the same name in the same scope. The switch statement itself defines a scope, but each case clause does not. If you want a scope within a case clause, then you'll have to provide one yourself:
case '0':
{
bool tf(true);
break;
}
Although it's not clear what good that is; you're declaring a local variable then ignoring it. Perhaps you meant to set the global variable:
case '0':
tf = true;
break;
so you could then check it with
if (tf) // NOT if (bool tf = true) - that also declares a new local variable
or, less freakily, perhaps you want to return a value:
bool IsNumber(char x) {
switch (x) {
case '0':
// and so on
return true;
default:
return false;
}
}
and test it with
if (IsNumber(x)) {
cout << "True" << endl;
} else {
cout << "False" << endl;
}
or, if verbosity isn't your thing
cout << (IsNumber(x) ? "True" : "False") << endl;
or even
cout << boolalpha << IsNumber(x) << endl;
You should probably take some time to read an introductory book until you're comfortable with the basics such as scopes, declarations and definitions. Here are some recommendations.
You haven't assigned anything to tf, for comparison operators we want =='s instead of just the ='s.
if (tf == true) {
}
You can only define a variable one you can assign it as many times as you need.
bool tf = false
means I am define a variable and assigning it
if I just want to assign it later
tf = false
if I want to do a conditional test
if (tf){do stuff}
You have x defined at the very top as a global variable, and then try and define it again in main. You have to pick one or the other, or rename one. What you probably want to do is get rid of the one in main.
You also have your bools compared as = instead of how they should be like ==.
Edit: You actually don't need the comparison in there at all.
if(tf){
cout << "True\n"
}
else cout << "False\n"
That will see if tf is true and output true and if not, output false.
Hello I have the code below:
enum {a, b, c, d, ..., z} abc;
int main()
{
int val = 20;
if (val == a || val == b ||val == c||val == d..... || val == z)
{
/*Do something*/
}
}
Is there any other way so that we can skip the OR operation because if there are 1000s of enum members then how can we do ahead with checking with all members.
Please help.
A modern compiler should just be able to optimize such code if, as in your case, the value of the expression is known at compile time. For readability and error checking I think that using a switch would be better:
switch (val) {
case a:;
case b:;
....
// your code goes here
}
As said, performance wise there shouldn't be much difference, the compiler will transform this to a table lookup (or other clever things) if appropriate or completely optimize it out if val is known at compile time.
But you can have the advantage of error checking compilers, here. If you don't have a default case, most compilers will warn you if you omit one of the enumeration constants. Also I think that this is clearer, since it doesn't repeat the evaluation of val all over the place.
other(faster) solution will be the following
bool isInenum (int val)
{
bool retVal = false
switch(val)
{
case a:
case b:
case c:
case d:
{
retVal = true;
}
}
return retVal;
}
Since enumerator values are assigned sequentially, putting an if statement like this would be enough:
if(val<=z)
You could use a map in C++. With a map you can write a compact test without the numerous == and ||.
But you first need to initialize a map and I'm not sure if you can do this initialization in a compact way for an arbitrary enum.
#include <iostream>
#include <map>
using namespace std;
enum abc { a = 1, b = -1, c = 3, d = 0 };
int main()
{
map<int, int> m;
m[a] = m[b] = m[c] = m[d] = 1;
cout << "b is " << ((m.find(b) == m.end()) ? "NOT " : "") << "in m" << endl;
cout << "3 is " << ((m.find(3) == m.end()) ? "NOT " : "") << "in m" << endl;
cout << "10 is " << ((m.find(10) == m.end()) ? "NOT " : "") << "in m" << endl;
return 0;
}
Output (ideone):
b is in m
3 is in m
10 is NOT in m