2

I'm working on a small project on Dev-C++. I'm trying to make a bot to ask you some questions, but I can't use the switch statetments with the strings. Every time I try to do so it shows error! I also tried to change the srings to normal int variables but when I the code runs all at once after answering the first question! Does anyone knows how to fix any of these situations?

Here is my code:

// #include "stdafx";

#include <iostream>
#include <string>
#include <stdio.h>
#include <string.h>

using namespace std;

int main()
{
    string comida;
    string nome;
    string idade;
    string pais;

    cout << "Ola, o meu nome e Aleksandar. Qual e o teu nome?" << endl; //Ask for nome
    cin >> nome; //Recieve variable nome

    cout << "Es de que pais, " << nome << "?" << endl; //Ask for pais
    cin >> pais; //Receive pais
    cout << pais << " e um pais bonito. " << "Eu sou de Portugal!" << endl; 

    cout << "Quantos anos tens " << nome << "?" << endl; //Ask for idade
    cin >> idade; //Receive variable idade

    switch (idade) {
       case 21:
          cout << "O meu irmao tambem tem 21 anos!" << endl;
          break;
    }
    cout << "Eu tenho 28" << endl;

    cout << "Qual e a tua comida preferida?" << endl; //Ask for comida
    cin >> comida; //Receive variable comida

    cout << "Tambem gosto muito de " << comida << ". Mas gosto mesmo e de Vatruchka!" << endl;
    cout << "Xau " << nome << "!" << endl;
}
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055

4 Answers4

2

A switch will not compile when non-intergal (i.e. string, float, bool, vector, etc...) data-types are assigned to the switch's case: statements. Furthermore, its necessary that the values assigned to the case: statements are const.

In other words:

Switches must use "constant integral data-types" (i.e. 'enum', 'int', 'char', etc...), and cannot implament strings as conditional statements, however; that is not the same as saying that strings cannot be used in a conditional statement, they very much can be & often are — see the example below:


    std::string s;
    std::cin >> s;

    if (s == "Yes")
    {
       std::cout << "You said yes!" << std::endl;
    } 
    else if (s == "No")
    {
       std::cout << "You said no?"  << std::endl;
    }
    else 
    {
       std::cout << "You said something I don't understand"  << std::endl;
    }
So to finish this answer, you can see that you can achieve the same thing you could with a switch statement using if/else blocks. It may, or it may not, be ideal for your situation, but this is how C++, and switch statements work, so your stuck with it — like it, or not...
JΛYDΞV
  • 8,532
  • 3
  • 51
  • 77
Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • 1
    In practice, most of the time I've needed to "switch" on a string, I've found a map to pointers to functions or polymorphic functional objects to be the best solution. (Most of the time. There have been a few exceptions where I've chained `if...else if...`.) – James Kanze Mar 01 '15 at 00:00
  • 1
    Sure, but that is probably not the level of discussion the OP wants in this particular case. – Mats Petersson Mar 01 '15 at 00:11
2

If the string contains a number, switch(std::stoi(idade)) will work. But that doesn't work if idade contains something else.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • And it means, of course, that you have to have a `try` block somewhere. – James Kanze Feb 28 '15 at 23:58
  • Probably not important in this case, but I believe this would introduce a security issue as the generated code uses the integer as an index for the next instruction to execute. – Xiao Feb 28 '15 at 23:58
  • 1
    @Xiao: No security issue here. There's an implicit `default: break`. – MSalters Mar 01 '15 at 00:07
  • @MSalters Oh cool. Is that a language specification? – Xiao Mar 01 '15 at 00:13
  • 1
    @Xiao: Yes, that is how `switch` works. You are writing C++, not assembly. It's nowhere near as close to the metal as you seem to think! – Lightness Races in Orbit Mar 01 '15 at 00:16
  • @LightnessRacesinOrbit haha sure. I'm trying to find it in the spec, but I can only see `If no case matches and if there is no default then none of the statements in the switch is executed.` – Xiao Mar 01 '15 at 00:59
  • 1
    @Xiao: Right, and it doesn't say "but some random piece of code that happens to be in your desktop computer's memory may be executed instead". C++ is an abstraction. It's a lot safer than you think. It will _never_, for a valid, well-defined program, result in arbitrary pieces of code being executed. I can't quote you the part of the standard that ensures that because it's spread all over the place. It's inherent. – Lightness Races in Orbit Mar 01 '15 at 01:36
  • @LightnessRacesinOrbit Sure, but as far as I can tell it's not defined in the standard what will happen if there's no default and it doesn't match. If a compiler wanted to implement the switch in that way, couldn't they do it and still be standards compliant? – Xiao Mar 01 '15 at 02:20
  • 1
    @Xiao: And from an assembly perspective, "use as an index for the next instruction" doesn't make sense anyway. Consider `case 0:` ! – MSalters Mar 01 '15 at 11:56
1

You can't use strings — switch only works for integral case types (i.e. integers and enums).

You could use something like this, instead:

if (idade == "21") { cout << "...\n"; }
else if (idade == "something else") { cout << "...\n"; }

You describe that the code runs all at once when you change to using integers. It's possible you're forgetting to include break in each case clause.

Tim Ruddick
  • 1,375
  • 16
  • 24
0

If you have a set of different strings that you are expecting then you can set up an enum and a map (I use the word map loosely here - I don't mean the actual map in C++, although I know it is possible to do something similar with it)

Use this to turn the input into an enum and then you can run a switch on the enum

E.g.

enum class ANSWER
{
    ANSWER_1,
    ANSWER_2
};

class AnswerMap    \\set up this class like a singleton
{
    std::vector<std::pair<std::string, ANSWER>> _answer_map = {
        std::make_pair("Answer 1 string", ANSWER::ANSWER_1),
        std::make_pair("Answer 2 string", ANSWER::ANSWER_2)
    }

    std::string String(ANSWER answer);    \\have this function loop through this->_answer_map until finding the pair with the second item as the given enum and return the corresponding string

    ANSWER Enum(std::string answer);    \\have this function do the same as this->String but find the pair where the string matches and then return the corresponding enum
}
Kvothe
  • 1,819
  • 2
  • 23
  • 37
  • 1
    this seems more complicated and slower than a `map` for no apparent reason – M.M Mar 01 '15 at 01:44
  • I used this when I had to make a solution and didn't have the time to spend learning how to use a map. It is slower but it wasn't the bottle-neck in my application so it didn't matter – Kvothe Mar 01 '15 at 09:20