Why can't the switch statement be applied to strings?
Asked Answered
B

23

331

Compiling the following code gives the error message: type illegal.

int main()
{
    // Compilation error - switch expression of type illegal
    switch(std::string("raj"))
    {
    case"sda":
    }
}

You cannot use string in either switch or case. Why? Is there any solution that works nicely to support logic similar to switch on strings?

Bradbradan answered 16/3, 2009 at 12:14 Comment(2)
Is there a boost alternative that hides the map construction,enum behind a MACRO?Phototypography
@Phototypography I'm not sure about boost but it's easy to write such macros. In case of Qt then you can hide the mapping with QMetaEnum Plyler
O
260

The reason why has to do with the type system. C/C++ doesn't really support strings as a type. It does support the idea of a constant char array but it doesn't really fully understand the notion of a string.

In order to generate the code for a switch statement the compiler must understand what it means for two values to be equal. For items like ints and enums, this is a trivial bit comparison. But how should the compiler compare 2 string values? Case sensitive, insensitive, culture aware, etc ... Without a full awareness of a string this cannot be accurately answered.

Additionally, C/C++ switch statements are typically generated as branch tables. It's not nearly as easy to generate a branch table for a string style switch.

Oncoming answered 16/3, 2009 at 12:30 Comment(12)
The branch table argument shouldn't apply - that's only one possible approach available to a compiler author. For a production compiler, one has to frequently use several approaches depending on the complexity of the switch.Nostoc
@plinth, I put it there mostly for historical reasons. A lot of the "why does C/C++ do this" questions can easily be answered by the history of the compiler. At the time they wrote it, C was glorified assembly and hence switch really was a convenient branch table.Oncoming
@Nostoc (cont) yes they could have updated it since then but C/C++ is annoyingly slow at changing the way they do things. For instance, it took till C99 to get a boolean type into C!Oncoming
still I think it would be great if the compiler simply transformed switch into "if" using operator== and the problem would be solved... Now we have to think about these constructions as totally different with some similarities...Frentz
I vote down because i don't understand how could the compiler knows how to compare 2 string values in if statements but forget the way to do the same thing in switch statements.Lammond
I don't think the first 2 paragraphs are valid reasons. Especially since C++14 when std::string literals were added. It is mostly historical. But one problem that does come to mind is that with the way switch works currently, duplicate cases must be detected at compile-time; however this might not be so easy for strings (considering run-time locale selection and so on). I suppose that such a thing would have to require constexpr cases, or add in unspecified behaviour (never a thing that we want to do).Pilose
@Pilose I think the locale specific switch issue is a red herring. In the history of switch statements, has anyone ever done cross locale switching inside their code? This is just inviting a nightmare of security fail. A switch is a programming language thing, not a human language thing. As for constexpr you can now actually hash the string value passed in and the switch values to get to a numeric based switch. It is still ugly in that you need a constexpr hash function. Seems like the compiler should just do that for you.Sundberg
There is a clear definition of how to compare two std::string values or even an std::string with a const char array (namely by using operator==) there is no technical reason that would prevent the compiler from generating a switch statement for any type that provides that operator. It would open some questions about things like lifetime of the lables but all in all this is primarily a language design decision, not a technical difficulty.Atkins
The reason about the compiler not knowing how to compare a string is poor. Better reason is the reticence of the c++ standard committee to make std::string, std::wstring and other string types first citizen in the language.Moramorabito
@Lammond The compiler uses std::string::operator==(std::string const &rhs) to compare two strings in an if statement. So technically the compiler itself does NOT know how to compare two strings. It relies on code that someone has written to do the comparison.Tomikotomkiel
Does not address the "Is there any solution that works nicely..." part.Jittery
@Pilose basic_string::operator== does not consider the locale, neither should a hypothetical string-switch. For all I am concerned, it should work like unoredered_map<string, void(*)()>.Shadow
M
75

As mentioned previously, compilers like to build lookup tables that optimize switch statements to near O(1) timing whenever possible. Combine this with the fact that the C++ Language doesn't have a string type - std::string is part of the Standard Library which is not part of the Language per se.

I will offer an alternative that you might want to consider, I've used it in the past to good effect. Instead of switching over the string itself, switch over the result of a hash function that uses the string as input. Your code will be almost as clear as switching over the string if you are using a predetermined set of strings:

enum string_code {
    eFred,
    eBarney,
    eWilma,
    eBetty,
    ...
};

string_code hashit (std::string const& inString) {
    if (inString == "Fred") return eFred;
    if (inString == "Barney") return eBarney;
    ...
}

void foo() {
    switch (hashit(stringValue)) {
    case eFred:
        ...
    case eBarney:
        ...
    }
}

There are a bunch of obvious optimizations that pretty much follow what the C compiler would do with a switch statement... funny how that happens.

Moravia answered 16/3, 2009 at 12:52 Comment(7)
This is really disappointing because you are not actually hashing. With modern C++ you can actually hash at compile time using a constexpr hash function. Your solution looks clean but has all that nasty if ladder going on unfortunately. The map solutions below would be better and avoid the function call as well. Additionally by using two maps you can have built in text for error logging as well.Sundberg
You can also avoid the enum with lambdas: https://mcmap.net/q/23355/-why-can-39-t-the-switch-statement-be-applied-to-stringsStedt
Could hashit be a constexpr function? Given that you pass in a const char * rather than a std::string.Hance
But why? You get all the time use of the if statement execution on top of a switch. Both have minimal impact, but the performance advantages with a switch are erased by the if-else lookup. Just using an if-else should be marginally faster, but more importantly, significantly shorter.Dukie
I agree with @Zoe, what's the point of all this extra code when a simple if/else will suffice. If I came across this example in the field, I would delete it and refactor it to be an if else, which is more readable and sustainable for teams. Even the smaller more simple version of this using a constexpr hash function is ugly and unreadable.Load
@ZoestandswithUkraine If you are to use the switch statement only once, then yes, it's hard to see the advantages. Even then, one may argue the fallthrough of the switch could be useful. Anyway, even this approach helps make it easier to express many cases of fallthrough logic if you have many such switches to write. But even in that case the constexpr solutions would be much better. (This definitely lacks the performance advantages.)Cinerator
If you really do want to use a hash, then replace hashit with a std::unordered_map<std::string, enum string_code> which will most likely use a hash function under the hood. With the associated performance benefit. You still need to check that you don't get unordered_map<...>.end() as the return from the .find() call, but that's a simple comparison, which would then map to your default: case.Tomikotomkiel
I
53

C++

constexpr hash function:

constexpr unsigned int hash(const char *s, int off = 0) {                        
    return !s[off] ? 5381 : (hash(s, off+1)*33) ^ s[off];                           
}                                                                                

switch( hash(str) ){
case hash("one") : // do something
case hash("two") : // do something
}

Update:

The example above is C++11. There constexpr function must be with single statement. This was relaxed in next C++ versions.

In C++14 and C++17 you can use following hash function:

constexpr uint32_t hash(const char* data, size_t const size) noexcept{
    uint32_t hash = 5381;

    for(const char *c = data; c < data + size; ++c)
        hash = ((hash << 5) + hash) + (unsigned char) *c;

    return hash;
}

Also C++17 have std::string_view, so you can use it instead of const char *.

In C++20, you can try using consteval.

Istria answered 12/10, 2017 at 14:7 Comment(8)
You have to make sure that none of your cases hash to the same value. And even then, you may have some mistakes where other strings that hash to, for example, the same value as hash("one") will incorrectly do the first "something" in your switch.Dita
I know, but if it hashes to same value it wont compile and you will notice it on time.Istria
Good point - but that doesn't solve the hash collision for other strings that are not part of your switch. In some cases that might not matter, but if this was a generic "go-to" solution I could imagine it being a security issue or the like at some point.Dita
You can add a operator "" to make the code more beautiful. constexpr inline unsigned int operator "" _(char const * p, size_t) { return hash(p); } And use it like case "Peter"_: break; DemoBeaston
hbfs.wordpress.com/2017/01/10/… is similarJittery
the hash function below throws a integral constant overflow warning by me. Do you know how it happens?Langrage
For sure is not because two strings are hashed to same value. Could be something related of the string you are hashing. The hash function is from DJB, bit changed to avoid warnings for changing between integral types. If you can, send me a string you are trying to hash.Istria
In C++17, the loop can be improved because of std::string_view to: constexpr uint32_t hash(const std::string_view data) noexcept { uint32_t hash = 5385; for (const auto &e : data) hash = ((hash << 5) + hash) + e; return hash; }Unconditional
S
21

C++ 11 update of apparently not @MarmouCorp above but http://www.codeguru.com/cpp/cpp/cpp_mfc/article.php/c4067/Switch-on-Strings-in-C.htm

Uses two maps to convert between the strings and the class enum (better than plain enum because its values are scoped inside it, and reverse lookup for nice error messages).

The use of static in the codeguru code is possible with compiler support for initializer lists which means VS 2013 plus. gcc 4.8.1 was ok with it, not sure how much farther back it would be compatible.

/// <summary>
/// Enum for String values we want to switch on
/// </summary>
enum class TestType
{
    SetType,
    GetType
};

/// <summary>
/// Map from strings to enum values
/// </summary>
std::map<std::string, TestType> MnCTest::s_mapStringToTestType =
{
    { "setType", TestType::SetType },
    { "getType", TestType::GetType }
};

/// <summary>
/// Map from enum values to strings
/// </summary>
std::map<TestType, std::string> MnCTest::s_mapTestTypeToString
{
    {TestType::SetType, "setType"}, 
    {TestType::GetType, "getType"}, 
};

...

std::string someString = "setType";
TestType testType = s_mapStringToTestType[someString];
switch (testType)
{
    case TestType::SetType:
        break;

    case TestType::GetType:
        break;

    default:
        LogError("Unknown TestType ", s_mapTestTypeToString[testType]);
}
Sundberg answered 10/12, 2014 at 0:7 Comment(2)
I should note that I later found a solution requiring string literals and compile time calculations (C++ 14 or 17 I think) where you can hash the case strings at compile time and hash the switch string at runtime. It would be worthwhile for really long switches perhaps but certainly even less backwards compatible if that matters.Sundberg
Could you share the compile-time solution here please? Thanks!Australorp
S
16

std::map + C++11 lambdas pattern without enums

Here's a standard-compliant way to do it that does not involve any repetition in the form of named enums that only get used once.

We use unordered_map for the potential amortized O(1): What is the best way to use a HashMap in C++?

#include <functional>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>

int main() {
    int result;
    const std::unordered_map<std::string,std::function<void()>> m{
        {"one",   [&](){ result = 1; }},
        {"two",   [&](){ result = 2; }},
        {"three", [&](){ result = 3; }},
    };
    const auto end = m.end();
    std::vector<std::string> strings{"one", "two", "three", "foobar"};
    for (const auto& s : strings) {
        auto it = m.find(s);
        if (it != end) {
            it->second();
        } else {
            result = -1;
        }
        std::cout << s << " " << result << std::endl;
    }
}

Output:

one 1
two 2
three 3
foobar -1

Usage inside methods with static

To use this pattern efficiently inside classes, initialize the lambda map statically, or else you pay O(n) every time to build it from scratch.

Here we can get away with the {} initialization of a static method variable: Static variables in member functions , but we could also use the methods described at: How do you initialize static data members, similar to static constructors?

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 <string>
#include <unordered_map>
#include <vector>

class RangeSwitch {
public:
    void method(std::string key, int &result) {
        static const std::unordered_map<std::string,std::function<void(int&)>> m{
            {"one",   [](int& result){ result = 1; }},
            {"two",   [](int& result){ result = 2; }},
            {"three", [](int& result){ result = 3; }},
        };
        static const auto end = m.end();
        auto it = m.find(key);
        if (it != end) {
            it->second(result);
        } else {
            result = -1;
        }
    }
};

int main() {
    RangeSwitch rangeSwitch;
    int result;
    std::vector<std::string> strings{"one", "two", "three", "foobar"};
    for (const auto& s : strings) {
        rangeSwitch.method(s, result);
        std::cout << s << " " << result << std::endl;
    }
}
Stedt answered 25/2, 2017 at 22:51 Comment(4)
Note that there is a difference between this approach and a switch statement. Duplication of case values in a switch statement is a compile time failure. Using std::unordered_map silently accepts duplicate values.Moravia
I'm soooo confused, I fail to see what's the point of lambdas here 🤦 Can't you just do map<string, int> instead of jumping hoops with lambdas that set result to the int?Durga
@PavelP this approach is DRYer because you don't have to write those arbitrary ints twice, this code is clearly superior from a reader/writer point of view. Performance wise, we'd have to check. The int map does one extra hashmap access. This one a func call if unoptimized.Stedt
Not sure where you see any superiority. This code is convoluted mess imo. Normal code makes more sense: godbolt.org/z/f4s85rMaTDurga
C
15

The problem is that for reasons of optimization the switch statement in C++ does not work on anything but primitive types, and you can only compare them with compile time constants.

Presumably the reason for the restriction is that the compiler is able to apply some form of optimization compiling the code down to one cmp instruction and a goto where the address is computed based on the value of the argument at runtime. Since branching and and loops don't play nicely with modern CPUs, this can be an important optimization.

To go around this, I am afraid you will have to resort to if statements.

Collage answered 16/3, 2009 at 12:24 Comment(1)
An optimized version of a switch statement that can work with strings is definitely possible. The fact that they can't reuse the same code path they use for primitive types doesn't mean that they can't make std::string and others first citizen in the language and support them in switch statement with an efficient algorithm.Moramorabito
N
13

To add a variation using the simplest container possible (no need for an ordered map)... I wouldn't bother with an enum--just put the container definition immediately before the switch so it'll be easy to see which number represents which case.

This does a hashed lookup in the unordered_map and uses the associated int to drive the switch statement. Should be quite fast. Note that at is used instead of [], as I've made that container const. Using [] can be dangerous--if the string isn't in the map, you'll create a new mapping and may end up with undefined results or a continuously growing map.

Note that the at() function will throw an exception if the string isn't in the map. So you may want to test first using count().

const static std::unordered_map<std::string,int> string_to_case{
   {"raj",1},
   {"ben",2}
};
switch(string_to_case.at("raj")) {
  case 1: // this is the "raj" case
       break;
  case 2: // this is the "ben" case
       break;


}

The version with a test for an undefined string follows:

const static std::unordered_map<std::string,int> string_to_case{
   {"raj",1},
   {"ben",2}
};
// in C++20, you can replace .count with .contains
switch(string_to_case.count("raj") ? string_to_case.at("raj") : 0) {
  case 1: // this is the "raj" case
       break;
  case 2: // this is the "ben" case
       break;
  case 0: //this is for the undefined case

}
Neddra answered 3/7, 2016 at 5:2 Comment(0)
C
7

In C++ and C switches only work on integer types. Use an if else ladder instead. C++ could obviously have implemented some sort of swich statement for strings - I guess nobody thought it worthwhile, and I agree with them.

Chilopod answered 16/3, 2009 at 12:17 Comment(4)
agreed,but do you know what made this not possible to useBradbradan
History? Switching on real numbers, pointers and structs (C's only other data types) doesn't make sanse, so C limitted it to integers.Chilopod
Especially if you switch on classes that allow implicit conversions you'll have a really good time once.Joelynn
This does not answer the question. It is already abundantly clear that switches do not work on strings and that an if-else ladder can be used instead, however both the title and body of the question ask why.Cinerator
O
6

Why not? You can use switch implementation with equivalent syntax and same semantics. The C language does not have objects and strings objects at all, but strings in C is null terminated strings referenced by pointer. The C++ language have possibility to make overload functions for objects comparision or checking objects equalities. As C as C++ is enough flexible to have such switch for strings for C language and for objects of any type that support comparaison or check equality for C++ language. And modern C++11 allow to have this switch implementation enough effective.

Your code will be like this:

std::string name = "Alice";

std::string gender = "boy";
std::string role;

SWITCH(name)
  CASE("Alice")   FALL
  CASE("Carol")   gender = "girl"; FALL
  CASE("Bob")     FALL
  CASE("Dave")    role   = "participant"; BREAK
  CASE("Mallory") FALL
  CASE("Trudy")   role   = "attacker";    BREAK
  CASE("Peggy")   gender = "girl"; FALL
  CASE("Victor")  role   = "verifier";    BREAK
  DEFAULT         role   = "other";
END

// the role will be: "participant"
// the gender will be: "girl"

It is possible to use more complicated types for example std::pairs or any structs or classes that support equality operations (or comarisions for quick mode).

Features

  • any type of data which support comparisions or checking equality
  • possibility to build cascading nested switch statemens.
  • possibility to break or fall through case statements
  • possibility to use non constatnt case expressions
  • possible to enable quick static/dynamic mode with tree searching (for C++11)

Sintax differences with language switch is

  • uppercase keywords
  • need parentheses for CASE statement
  • semicolon ';' at end of statements is not allowed
  • colon ':' at CASE statement is not allowed
  • need one of BREAK or FALL keyword at end of CASE statement

For C++97 language used linear search. For C++11 and more modern possible to use quick mode wuth tree search where return statement in CASE becoming not allowed. The C language implementation exists where char* type and zero-terminated string comparisions is used.

Read more about this switch implementation.

Odyssey answered 11/10, 2016 at 11:9 Comment(0)
B
4

I think the reason is that in C strings are not primitive types, as tomjen said, think in a string as a char array, so you can not do things like:

switch (char[]) { // ...
switch (int[]) { // ...
Bruxelles answered 16/3, 2009 at 12:31 Comment(1)
Without looking it up, a character array would likely degenerate to a char *, which converts directly to an integral type. So, it might well compile, but it certainly won't do what you want.Sensitivity
F
4

In c++ strings are not first class citizens. The string operations are done through standard library. I think, that is the reason. Also, C++ uses branch table optimization to optimize the switch case statements. Have a look at the link.

http://en.wikipedia.org/wiki/Switch_statement

Flection answered 16/3, 2009 at 13:28 Comment(0)
D
3

Late to the party, here's a solution I came up with some time ago, which completely abides to the requested syntax.

#include <uberswitch/uberswitch.hpp>

int main()
{
    uswitch (std::string("raj"))
    {
        ucase ("sda"): /* ... */ break;  //notice the parenthesis around the value.
    }
}

Here's the code: https://github.com/falemagn/uberswitch

Deprived answered 29/8, 2020 at 15:58 Comment(0)
S
3

hare's comment to Nick's solution is really cool. here the complete code example (in C++11):

constexpr uint32_t hash(const std::string& s) noexcept
{
    uint32_t hash = 5381;
    for (const auto& c : s)
        hash = ((hash << 5) + hash) + (unsigned char)c;
    return hash;
}

constexpr inline uint32_t operator"" _(char const* p, size_t) { return hash(p); }

std::string s = "raj";
switch (hash(s)) {
case "sda"_:
    // do_something();
    break;
default:
    break;
}
Scroll answered 26/10, 2021 at 9:37 Comment(2)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Cartel
This is very cool! I think it would help if the answer reiterated on what the code is doing, i.e. using constexpr hashing and overloading "" _ so that it would stand well on its own as an answer.Cinerator
C
2

You could put the strings in an array and use a constexpr to convert them to indices at compile time.

constexpr const char* arr[] = { "bar", "foo" };
constexpr int index(const char* str) { /*...*/ }

do_something(std::string str)
{
    switch(quick_index(str))
    {
        case index("bar"):
            // ...
            break;

        case index("foo"):
            // ...
            break;

        case -1:
        default:
            // ...
            break;
    }

For quick_index, which doesn't have to be constexpr, you could e.g. use an unordered_map to do it O(1) at runtime. (Or sort the array and use binary search, see here for an example.)

Here's a full example for C++11, with a simple custom constexpr string comparer. Duplicate cases and cases not in the array (index gives -1) will be detected at compile time. Missing cases are obviously not detected. Later C++ versions have more flexible constexpr expressions, allowing for simpler code.

#include <iostream>
#include <algorithm>
#include <unordered_map>

constexpr const char* arr[] = { "bar", "foo", "foobar" };

constexpr int cmp(const char* str1, const char* str2)
{
    return *str1 == *str2 && (!*str1 || cmp(str1+1, str2+1));
}

constexpr int index(const char* str, int pos=0)
{
    return pos == sizeof(arr)/sizeof(arr[0]) ? -1 : cmp(str, arr[pos]) ? pos : index(str,pos+1);
}

int main()
{
    // initialize hash table once
    std::unordered_map<std::string,int> lookup;
    int i = 0;
    for(auto s : arr) lookup[s] = i++;
    auto quick_index = [&](std::string& s)
        { auto it = lookup.find(s); return it == lookup.end() ? -1 : it->second; };
    
    // usage in code
    std::string str = "bar";
    
    switch(quick_index(str))
    {
        case index("bar"):
            std::cout << "bartender" << std::endl;
            break;

        case index("foo"):
            std::cout << "fighter" << std::endl;
            break;

        case index("foobar"):
            std::cout << "fighter bartender" << std::endl;
            break;
            
        case -1:
        default:
            std::cout << "moo" << std::endl;
            break;
    }
}
Crescen answered 16/5, 2021 at 18:20 Comment(0)
O
2

Here is an elegant way to switch on compile time "strings" (actually string_view) with zero runtime overhead. One can use a constexpr array of strings and then switch on a consteval function as shown below. The compiler output is identical to using only integers -- no additional memory or runtime performance is paid. Compiling code is available here https://godbolt.org/z/KqjKrczv5

#include <fmt/core.h>
#include <array>
#include <string_view>

static constexpr auto MY_MODES = std::array< std::string_view, 3 >{ "AAA", "BBB", "CCC" };

//use consteval to eliminate runtime conversions, zero runtime overhead!
consteval int mode( std::string_view s )
{
    for( int i = 0; i < MY_MODES.size(); ++i )
        if( std::string_view{ s } == MY_MODES[i] )
           return i;
}

int main()
{
    auto curMode = mode("CCC"); //use the "string_view"
    fmt::print( "curMode is {:d}\n", curMode );

    switch( curMode )
    {
        case mode( "AAA" ): fmt::print( "aaa" ); break;
        case mode( "BBB" ): fmt::print( "bbb" ); break; 
        case mode( "CCC" ): fmt::print( "ccc" ); break;
        default:
           return -1;
    }   
    return 42;
}

Using the approach, the assembly is optimized like a typical switch statement -- no added CPU instructions since everything is evaluated at compile time. Assembly Output

Oaxaca answered 13/4, 2023 at 21:30 Comment(1)
Looking at the ASM in godbolt, I don't think this functions like a typical switch as each time a new "mode" is added another cmp and je/jg instruction is created. Instead, a switch statement should just jmp to a label by an offsetSevere
C
1

In C++ you can only use a switch statement on int and char

Curule answered 16/3, 2009 at 12:15 Comment(4)
A char turns into an int, too.Rigmarole
Pointers can, too. That means you can sometimes compile something that would make sense in a different language, but it won't run right.Sensitivity
You can actually use long and long long, which won't turn into int. There's no risk of truncation there.Arabesque
This answer is factually incorrect. You can use Any expression of integral or enumeration type, or of a class type contextually implicitly convertible to an integral or enumeration typeNeddra
H
1

You can use switch on strings. What you need is table of strings, check every string

char** strings[4] = {"Banana", "Watermelon", "Apple", "Orange"};

unsigned get_case_string(char* str, char** _strings, unsigned n)
{
    while(n)
    {
        n--
        if(strcmp(str, _strings[n]) == 0) return n;
    }
    return 0;
}

unsigned index = get_case_string("Banana", strings, 4);

switch(index)
{
    case 1: break;/*Found string `Banana`*/
    default: /*No string*/
}
Hoffarth answered 5/8, 2020 at 8:19 Comment(0)
I
0
    cout << "\nEnter word to select your choice\n"; 
    cout << "ex to exit program (0)\n";     
    cout << "m     to set month(1)\n";
    cout << "y     to set year(2)\n";
    cout << "rm     to return the month(4)\n";
    cout << "ry     to return year(5)\n";
    cout << "pc     to print the calendar for a month(6)\n";
    cout << "fdc      to print the first day of the month(1)\n";
    cin >> c;
    cout << endl;
    a = c.compare("ex") ?c.compare("m") ?c.compare("y") ? c.compare("rm")?c.compare("ry") ? c.compare("pc") ? c.compare("fdc") ? 7 : 6 :  5  : 4 : 3 : 2 : 1 : 0;
    switch (a)
    {
        case 0:
            return 1;

        case 1:                   ///m
        {
            cout << "enter month\n";
            cin >> c;
            cout << endl;
            myCalendar.setMonth(c);
            break;
        }
        case 2:
            cout << "Enter year(yyyy)\n";
            cin >> y;
            cout << endl;
            myCalendar.setYear(y);
            break;
        case 3:
             myCalendar.getMonth();
            break;
        case 4:
            myCalendar.getYear();
        case 5:
            cout << "Enter month and year\n";
            cin >> c >> y;
            cout << endl;
            myCalendar.almanaq(c,y);
            break;
        case 6:
            break;

    }
Impenetrable answered 8/3, 2016 at 16:58 Comment(1)
While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value.Threnode
G
0

More functional workaround to the switch problem:

class APIHandlerImpl
{

// define map of "cases"
std::map<string, std::function<void(server*, websocketpp::connection_hdl, string)>> in_events;

public:
    APIHandlerImpl()
    {
        // bind handler method in constructor
        in_events["/hello"] = std::bind(&APIHandlerImpl::handleHello, this, _1, _2, _3);
        in_events["/bye"] = std::bind(&APIHandlerImpl::handleBye, this, _1, _2, _3);
    }

    void onEvent(string event = "/hello", string data = "{}")
    {
        // execute event based on incomming event
        in_events[event](s, hdl, data);
    }

    void APIHandlerImpl::handleHello(server* s, websocketpp::connection_hdl hdl, string data)
    {
        // ...
    }

    void APIHandlerImpl::handleBye(server* s, websocketpp::connection_hdl hdl, string data)
    {
        // ...
    }
}
Guanase answered 18/11, 2018 at 9:39 Comment(0)
L
-1

You can't use string in switch case.Only int & char are allowed. Instead you can try enum for representing the string and use it in the switch case block like

enum MyString(raj,taj,aaj);

Use it int the swich case statement.

Lianneliao answered 16/3, 2009 at 12:28 Comment(1)
N
-1

That's because C++ turns switches into jump tables. It performs a trivial operation on the input data and jumps to the proper address without comparing. Since a string is not a number, but an array of numbers, C++ cannot create a jump table from it.

movf    INDEX,W     ; move the index value into the W (working) register from memory
addwf   PCL,F       ; add it to the program counter. each PIC instruction is one byte
                    ; so there is no need to perform any multiplication. 
                    ; Most architectures will transform the index in some way before 
                    ; adding it to the program counter

table                   ; the branch table begins here with this label
    goto    index_zero  ; each of these goto instructions is an unconditional branch
    goto    index_one   ; of code
    goto    index_two
    goto    index_three

index_zero
    ; code is added here to perform whatever action is required when INDEX = zero
    return

index_one
...

(code from wikipedia https://en.wikipedia.org/wiki/Branch_table)

Neologism answered 24/3, 2016 at 19:46 Comment(1)
C++ doesn't require any particular implementation of its syntax. A naive cmp/jcc implementation can be just as valid according to the C++ Standard.Livvie
P
-1

in many cases you can avid extra work by pulling the first char from the string and switching on that. may end up having to do a nested switch on charat(1) if your cases start with the same value. anyone reading your code would appreciate a hint though because most would prob just if-else-if

Pieter answered 23/9, 2016 at 3:11 Comment(2)
This is not really a safe solution and would not recommend to do this. Going for if and else if statements is way more readable and much safer.Whit
What is dangerous about this solution, exactly @BeatScherrer? This is a pretty smart solution considering the setbacks. I imagine it's on the faster side too of potential options too. On that note, this could very much so help clean up a situation where you would otherwise use a massive if-else chain; this mimics a branching system. I think your point about if elses being more readable is pretty poorly informed (assuming the reason a switch is desired over an if-else chain is because there are so many string cases to handle, which is very reasonable).Cinerator
R
-2

Switches only work with integral types (int, char, bool, etc.). Why not use a map to pair a string with a number and then use that number with the switch?

Ritchey answered 11/8, 2012 at 4:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.