I am having some trouble using a switch statement with user input. Can anyone please explain what is going on? I am sorry if this is a noob question as I'm very used to Python and just started learning C++.
#include <iostream>
#include <string>
using namespace std;
#include <cstdlib>
int main()
{
string name;
cout << "Enter a name: ";
cin >> name;
switch (name){
case name == "Seth":
std::cout << "That's my name!";
return 0;
break;
case name == "seth":
std::cout << "Wow, you couldnt even put correct capitalization on my name...\n";
std::cout << "LEARN YOUR PRONOUNS AND GO BACK TO SCHOOL!";
return 0;
break;
case name == "SETH":
std::cout << "Ok ok you spelled my name right but make sure you turn off caps lock please";
return 0;
break;
default:
std::cout << "Come on get my name RIGHT!!!\n";
std::cout << "But you entered " << name;
}
return 0;
}
According to the C++ 17 Standard (9.4.2 The switch statement)
2 The condition shall be of integral type, enumeration type, or class
type. If of class type, the condition is contextually implicitly
converted (Clause 7) to an integral or enumeration type. If the
(possibly converted) type is subject to integral promotions (7.6), the
condition is converted to the promoted type. 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 a converted constant expression (8.20) of the adjusted type
of the switch condition. No two of the case constants in the same
switch shall have the same value after conversion.
The class std::string does not have an implicit conversion operator that converts an object of the type std::string to an integral or enumeration type.
So the expression in this switch statement
switch (name){
is invalid.
Also case labels like this
case name == "seth":
are syntactically incorrect.
You could resolve your problem with the switch statement for example the following way
#include <iostream>
#include <string>
#include <array>
#include <iterator>
#include <algorithm>
int main()
{
std::array<const char *, 3> names =
{
"Seth", "seth", "SETH"
};
std::string name;
std::cout << "Enter a name: ";
std::cin >> name;
size_t n = std::find( std::begin( names ), std::end( names ), name ) -
std::begin( names );
switch (n)
{
case 0:
std::cout << "That's my name!";
break;
case 1:
std::cout << "Wow, you couldnt even put correct capitalization on my name...\n";
std::cout << "LEARN YOUR PRONOUNS AND GO BACK TO SCHOOL!";
break;
case 2:
std::cout << "Ok ok you spelled my name right but make sure you turn off caps lock please";
break;
default:
std::cout << "Come on get my name RIGHT!!!\n";
std::cout << "But you entered " << name;
break;
}
}
#include <iostream>
#include <string>
int main()
{
std::string name;
std::cout << "Enter a name: ";
std::cin >> name;
if(name == "Seth")
{
std::cout << "That's my name!" << std::endl;
}
else if(name == "seth")
{
std::cout << "Wow, you couldn't even put correct capitalization on my name..." << std::endl;
std::cout << "LEARN YOUR PRONOUNS AND GO BACK TO SCHOOL!" << std::endl;
}
else if(name == "SETH")
{
std::cout << "Ok ok you spelled my name right but make sure you turn off caps lock please" << std::endl;
}
else
{
std::cout << "Come on get my name RIGHT!!!" << std::endl;
std::cout << "But you entered " << name << std::endl;
}
return 0;
}
As other people have told that you can not do string comparison in switch and provided a solution. But I would like to use enum class which I found more readable and int comparison much more faster than string comparison.
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <unordered_map>
int main() {
enum class Spellings { Seth, seth, SETH };
const std::unordered_map<std::string, Spellings> spellings_map{
{"Seth", Spellings::Seth},
{"seth", Spellings::seth},
{"Seth", Spellings::SETH},
};
std::string name;
std::cout << "Enter a name: ";
std::cin >> name;
auto result = spellings_map.find(name);
if (result == spellings_map.end()) {
std::cout << "Come on get my name RIGHT!!!\n";
std::cout << "But you entered " << name;
return -1;
}
switch (result->second) {
case Spellings::Seth:
std::cout << "That's my name!";
break;
case Spellings::seth:
std::cout << "Wow, you couldnt even put correct capitalization on "
"my name...\n";
std::cout << "LEARN YOUR PRONOUNS AND GO BACK TO SCHOOL!";
break;
case Spellings::SETH:
std::cout << "Ok ok you spelled my name right but make sure you "
"turn off caps lock please";
break;
}
}
Related
For example, if I type 'a', how do I print out the value of the variable a, i.e. "0 1" ?
string a = "0 1"; string c = "1 1";
string b = "0 1"; string d = "1 1";
cin>>
cout <<
Are you sure you're not looking for a map?
#include <iostream>
#include <string>
#include <map>
using namespace std;
int main(void) {
map<string, string> m;
m.insert(pair<string, string>("a", "0 1"));
m.insert(pair<string, string>("b", "0 1"));
m.insert(pair<string, string>("c", "1 1"));
m.insert(pair<string, string>("d", "1 1"));
string user_choice = "a";
cout << "Which letter?" << endl;
cin >> user_choice;
cout << "For " << user_choice << ": "
<< m.at(user_choice) << endl;
}
A std::map does exactly what it says. It maps values of one type to another, which is what it sounds like you're trying to do, and it does so without using variable names, which as others have pointed out, are discarded after compilation.
There are then all sorts of useful things that can be done to a map using the functions provided in the Standard Template Library.
You are asking about some kind of instrospection like some interpreted languages have, but C++ doesn't work that way.
This is not the right way to think about a C++ program (or in any other compiled language), the identifiers in the source code really disappear once the program is compiled.
In other words, there is no automatic relation between the character entered (e.g. "a") and the variable std::string a in the source code.
You have to manually do this:
#include<string>
int main(){
std::string a = "0 1";
std::string b = "0 1";
std::string c = "1 1";
std::string d = "1 1";
char x; std::cin >> x;
switch(x){
case 'a': std::cout << a << std::endl; break;
case 'b': std::cout << b << std::endl; break;
case 'c': std::cout << c << std::endl; break;
case 'd': std::cout << d << std::endl; break;
default: std::cout << "not such variable" << std::endl;
}
}
I am trying to make a text based C++ game.
I have a player class set up and I am now working on a method inside that class called displayMenu(), which will ask the user a variety of questions based on their player and send the data to the main/client code and then that data will create an object of player class via a constructor of player class.
My main question is...
I am trying to compare the input (string) from the user to the (string) they need to inputting, but I am getting an error which says "lower()" can not be resolved. I believe you have to compare each character, but I think there may be a more effective way to code this to provide simplicity and readability. What exactly am I doing wrong? What is the best way to code this?
Here is my code...
void Player::displayMenu(std::string& PlaName, std::string& cName, int& lvl, int& HP)
{
std::cout << "Player Creation Menu" << std::endl;
std::cout << "====================" << std::endl;
std::cout << std::endl;
std::cout << std::endl;
std::cout << "What is your name? " << std::endl;
std::cin >> PlaName;
std::cout << "What is your specitality? " << std::endl;
std::cin >> cName;
while(cName.lower() != "brawler" || cName.lower() != "thief" || cName.lower() != "persuader" || cName.lower()
!= "gunman")
{
std::cout << "That is not your true specitality..." << std::endl;
std::cout << "You must pick from { 'Brawler', 'Thief' , 'Persuader', 'Gunman' }" << std::endl;
std::cin >> cName;
}
}
I have several remarks on your original code:
Reading and comparing the strings seems like a bit complicated for this use-case. It is common to see usage of first character as identifier, to make it simpler.
The specialty is a classic example for enum (or enum class, which is enum that you must use always with it's name)
The displayMenu method should not be part of the Player class, since it isn't a behavior (an action) of the player. It should be part of the "Game"/"UI" class.
If you really want to use the complete string in order to identify the specialty, you can use the code examples in the first answer in the link Ayxan put in the comments.
Here is my proposed code:
#include <iostream>
constexpr char INVALID_CHARACTER_INPUT = '#';
enum class CharacterSpecialty
{
BRAWLER,
THIEF,
PERSUADER,
GUNMAN,
NUM_OF_SPECIALITY_TYPES
};
`
class Player
{
public:
Player(const std::string& player_name, CharacterSpecialty char_specialty) :
name(player_name),
specialty(char_specialty)
{
}
private:
std::string name;
CharacterSpecialty specialty;
};
Player displayMenuAndCreatePlayer()
{
std::cout << "\nPlayer Creation Menu\n" << "====================\n\n" << std::endl;
std::cout << "Enter your name: " << std::endl;
std::string player_name{};
std::cin >> player_name;
CharacterSpecialty char_specialty = CharacterSpecialty::NUM_OF_SPECIALITY_TYPES;
while(char_specialty == CharacterSpecialty::NUM_OF_SPECIALITY_TYPES)
{
std::cout << "What is your specialty?\n" << "[B]rawler, [T]hief, [P]ersuader or [G]unman"<< std::endl;
std::string char_type_input;
std::cin >> char_type_input;
char input = char_type_input.size() == 1 ? char_type_input[0] : INVALID_CHARACTER_INPUT;
switch(char_type_input)
{
case 'b':
case 'B':
char_specialty = CharacterSpecialty::BRAWLER;
break;
case 't':
case 'T':
char_specialty = CharacterSpecialty::THIEF;
break;
case 'p':
case 'P':
char_specialty = CharacterSpecialty::PERSUADER;
break;
case 'g':
case 'G':
char_specialty = CharacterSpecialty::GUNMAN;
break;
default:
std::cout << "Invalid Specialty Entered!\n" << std::endl;
break;
}
}
return Player(player_name, char_specialty);
}
int main()
{
Player player = displayMenuAndCreatePlayer();
}
I basically ask a user to input a string, let's say they input "ABC" or"DEF"
Then, I want to set a certain integer = 1 if ABC is entered and 2 if DEF is entered.
If anything else is entered, then I want it to say invalid value.
So at the end, I'll have the integer i assigned to 1 or 2 if a valid value was entered.
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
int main()
{
string input = "";
// How to get a string/sentence with spaces
cout << "Please enter a valid sentence (with spaces):\n>";
getline(cin, input);
cout << ".\n" << "You entered: " << input << endl << endl;
int m
if(input = ABC)
return 0;
}
Very easy:
#include <iostream>
#include <map>
#include <string>
int main()
{
std::map<std::string, int> const v { { "ABC", 1 }, { "DEF", 2 } };
for (std::string line; std::getline(std::cin, line); )
{
auto it = v.find(line);
if (it == v.end())
{
std::cout << "Input '" << line << "' is invalid.\n";
}
else
{
std::cout << "Your input value: " << it->second << "\n";
}
}
}
Your English spec:
” set a certain integer = 1 if ABC is entered and 2 if DEF is entered […] if anything else is entered, then I want it to say invalid value.
Expressed in C++:
if( s == "ABC" ) { x = 1; }
else if( s == "DEF" ) { x = 2; }
else { cout << "Invalid value." << endl; }
If neither of the specified possibilites is true, i.e. in the case of outputting "Invalid value.", then x keeps the value it had, which is how I interpret the word “set”.
At a higher level of abstraction, it seems like you want the user to specify one of two strings, namely “ABC” or “DEF”, which you want to have available as an integer id after the input operation.
Then there are two main possibilities:
you want the id to indicate also the case where the user specified some other string, e.g. a common value for this, or
you want the input operation to only return control when the user has inputted one of the two valid strings.
The last case effectively means that input operation must loop or logically fail. Logical failure can be expressed as an exception, or e.g. by calling std::terminate.
So as you see there is a range of possibilities here, i.e. above the simple “how do I translate this English to C++” the desired functionality is a bit under-specified.
#include <iostream>
#include <map>
#include <string>
#include <initializer_list>
using namespace std;
int main()
{
const std::map<std::string, int> lookupTable = { {"ABC", 1}, {"DEF", 2} };
string input = "";
int m;
while(true) {
cout << "Please enter a valid sentence (with spaces):\n>";
getline(cin, input);
std::map<std::string, int>::const_iterator it = lookupTable.find(input);
if (it != lookupTable.end()) {
m = it->second;
break;
}
}
cout << "You entered: " << input << endl << endl;
cout << "m = " << m << endl;
}
Second solution if you want your m const. This assumes your compiler supports lambda functions:
#include <iostream>
#include <map>
#include <string>
#include <initializer_list>
using namespace std;
int main()
{
const std::map<std::string, int> lookupTable = { {"ABC", 1}, {"DEF", 2} };
string input = "";
const int m = [&]() {
while(true) {
cout << "Please enter a valid sentence (with spaces):\n>";
getline(cin, input);
std::map<std::string, int>::const_iterator it = lookupTable.find(input);
if (it != lookupTable.end())
return it->second;
}
}();
cout << "You entered: " << input << endl << endl;
cout << "m = " << m << endl;
}
If your compiler does not support the above map initialization then you can use instead:
#include <iostream>
#include <map>
#include <string>
using namespace std;
std::map<std::string, int> initializeMap() {
std::map<std::string, int> map;
map["ABC"] = 1;
map["DEF"] = 2;
// add whatever else here
return map;
}
int main()
{
const std::map<std::string, int> lookupTable = initializeMap();
string input = "";
int m;
while(true) {
cout << "Please enter a valid sentence (with spaces):\n>";
getline(cin, input);
std::map<std::string, int>::const_iterator it = lookupTable.find(input);
if (it != lookupTable.end()) {
m = it->second;
break;
}
}
cout << "You entered: " << input << endl << endl;
cout << "m = " << m << endl;
}
I have this (I've just started to learn btw):
#include <iostream>
#include <string>
using namespace std;
int main()
{
string mystr;
cout << "Welcome, what is your name? ";
getline(cin, mystr);
cout << "Nice to meet you, " << mystr << endl;
cout << "May i call you 1 for short? (y/n)" << endl;
getline(cin, mystr);
}
I want to next say;
cout << "Thank you, 1" << endl;
OR:
cout << "Well ok, " << mystr << endl;
... based on whether or not the user has typed y or n. How would i go about this? I've had a look around but i don't really know how to word it. I'm using Visual Studio Express and it is a console application.
For a very simple way:
if (mystr == "1") {
// ...
}
But you should accustom yourself to more error checking, so check the state of the stream after getline:
getline(cin, mystr);
if (cin) {
if (mystr == "1") {
// ...
}
} else {
// error
}
And of course, you may want to support any number in the future, not just 1. Then you need to convert the input string to a number. See std::stoi if you use C++11, or look at the thousands of past Stackoverflow questions about string-to-number conversions :)
Edit: Just noticed that you actually wanted to check for "y". Well, that's the same then:
if (mystr == "y") {
// ...
}
You should use if-else statement. For example
#include <cctype>
//...
std::string name = mystr;
std::cout << "May i call you 1 for short? (y/n)" << std::endl;
std::getline( std::cin, mystr );
for ( char &c : mystr ) c = std::tolower( c );
if ( mystr == "y" )
{
name = "1";
std::cout << "Thank you, " << name << std::endl;
}
else
{
std::cout << "Well ok, " << name << std::endl;
}
Say I have a structure as follows
struct stock{
string ticker;
double price;
double volume;
double eps;
};
If I want to output one of the variables such as price when asked for it would I have to do a large if/else or switch statement to match up the user input with the member or is there a more elegant way to do it because I know stock.userInput does not work.
there's no special keyword to find your variable(sorry to burst your bubble), You would have to use a logical statement. It would go along:
cout << "What would you like to see? (1)Price (2)etc...etc...";
cin >> input;
switch(input)
{
case 1:
cout << Obj.Price;
break;
case 2:
cout << //....
break;
}
I personally like using keys and a switch statement, it tends to be a lot cleaner and easier to go back and modify later in the program.
struct stock s1;
cout<<" price is:"<< s1.price;
If you want to get rid of the large switch/if statement, you can use map with string and a pointer-to-member. Assuming your stock struct, you can use:
Define the map (for doubles here) and initialize it:
std::map<std::string,double stock::*> double_members;
double_members["price"]=&stock::price;
double_members["volume"]=&stock::volume;
double_members["eps"]=&stock::eps;
And use it to look up some values:
stock stock1;
std::string input;
std::cin >> input;
if (double_members.find(input)!=double_members.end())
std::cerr << "Value for " << input << " is: " << stock1.*double_members[input] << std::endl;
else
std::cerr << "There's no field called " << input << std::endl;
It's limited to a single type, but you can't have a statement like std::cerr << A; and have A's type resolved during runtime. If you care only about string (or any other, but always the same) representation of the values, then you can wrap maps for different types in a class that searches all of them and outputs the value converted to a string (or something).
But it's probably easier to have the if statement, unless the struct is really big.
If it's okay with you that it doesn't work with g++ 4.7.1 and earlier (but does work with Visual C++ 11.0 and later), then like …
#include <sstream> // std::ostringstream
#include <string> // std::string
using namespace std;
struct Stock
{
string ticker;
double price;
double volume;
double eps;
string toString() const
{
ostringstream stream;
stream
<< "Stock("
<< "ticker='" << ticker << "', "
<< "price=" << price << ", "
<< "volume=" << volume << ", "
<< "eps=" << eps
<< ")";
return stream.str();
}
Stock(): ticker(), price(), volume(), eps() {}
};
#include <iostream>
#include <regex>
#include <stdexcept>
#include <stdlib.h>
bool err( string const& s )
{
cerr << "!" << s << endl;
exit( EXIT_FAILURE );
}
string lineFromUser( string const& prompt )
{
string line;
cout << prompt;
getline( cin, line )
|| err( "oh my, failed to read line of input" );
return line;
}
void cppMain()
{
Stock stock;
stock.price = 1.23;
string const s = stock.toString();
cout << s << endl;
string const fieldname = lineFromUser( "Which field u want? " );
regex const valuespec( fieldname + "\\s*\\=\\s*([^,\\)]*)" ); //
smatch what;
if( regex_search( s, what, valuespec ) )
{
cout << "As we all know already, " << what.str() << "." << endl;
}
else
{
cout
<< "!Sorry, there's no field named '"
<< fieldname << "'"
<< endl;
}
}
int main()
{
try
{
cppMain();
return EXIT_SUCCESS;
}
catch( exception const& x )
{
cerr << "!" << x.what() << endl;
}
return EXIT_FAILURE;
}
Example usage:
[d:\dev\test]
> foo
Stock(ticker='', price=1.23, volume=0, eps=0)
Which field u want? eps
As we all know already, eps=0.
[d:\dev\test]
> _