'switch case on char*

It is a piece of code that gives me error:

const char* name = pAttr->Name(); // attribute name
const char* value = pAttr->Value(); // attribute value

switch(name) // here is where error happens: must have integral or enum type
{
case 'SRAD':    // distance from focal point to iso center
    double D = atof(value);
    break;
case 'DRAD':    // distance from iso center to detector
    break;
default:
    break;
}

The switch(name) is where error happens. It says it must be a integral or enum type. So how do I do switch case, or equivalent, on a char* type?



Solution 1:[1]

Another option is to use a local map to store integral values corresponding to the string values, get the integral value from the string, then, use switch on the integral value.

enum { SRAD = 1, DRAD, ... };

static std::map<std::string, int> localMap;
// Fill up the map.
if ( localMap.empty() )
{
   localMap["SRAD"] = SRAD;
   localMap["DRAD"] = DRAD;
}

const char* name = pAttr->Name(); // attribute name
const char* value = pAttr->Value(); // attribute value

int val = localMap[name];

switch (val)
{
    case SRAD:    // distance from focal point to iso center
    {
        double D = atof(value);
        break;
    }

    case DRAD:    // distance from iso center to detector
        break;

    default:      // name is unknown
        break;
}

Solution 2:[2]

Ok, this is totally, completely EVIL, but I have done it, and it does work:

// Must be a #define because an inline func won't give you a constant
#define MAKECODE(p) ((((p)[0])*0x01000000) \
                   + (((p)[1])*0x00010000) \
                   + (((p)[2])*0x00000100) \
                   +  ((p)[3]) )
// Note: I did not verify that the parenthesis matched. 

switch(MAKECODE(name))
{
  case MAKECODE("SRAD"):    // distance from focal point to iso center
     double D = atof(name);
     break;
  case MAKECODE("DRAD"):    // distance from iso center to detector
     break;
  default:
     break;
}

NOTE: BAD things will happen if the string name points to is less than 4 characters. Different bad things will happen is the string in the case statements are less than 4 characters (but probably just a compiler error).

Solution 3:[3]

this answer posted mostly for fun, but it will work if your name string is guaranteed to always be 4 bytes long.

#include <iostream>

using namespace std;

// precondition: name is exactly 4 chars in length
uint32_t convert(const char* name)
{
    uint32_t val = uint32_t(name[3])
    + (uint32_t(name[2]) << 8)
    + (uint32_t(name[1]) << 16)
    + (uint32_t(name[0]) << 24);
    return val;
}

int main()
{
    const char* name = "SRAD"; // attribute name
    const char* value = "10"; // attribute value


    switch(convert(name)) // convert the string value to integral type uint32_t
    {
        case 'SRAD':    // use arcane knowledge of C to construct an int32 representation of ascii digits
        {
            double D = atof(value);
            cout << "SRAD " << D << endl;
            break;
        }
        case 'DRAD':    // distance from iso center to detector
            cout << "some operation on value here " << endl;
            break;

        default:
            break;
    }

    return 0;
}

Solution 4:[4]

A switch statement can only evaluate an expression of an integral or enumeration type (or convertible to such a type), and the expression in each case label must be a constant expression.

'SRAD' is not a string literal. It's a character literal with an implementation-defined value of type int. (This is a nearly useless language feature that I've seen used by mistake more than I've seen it used correctly.)

If you want to use C-style language features, avoiding things like C++'s std::string, the equivalent would be an if/else chain:

if (strcmp(name, "SRAD") == 0) {
    // ...
}
else if (strcmp(name, "DRAD") == 0) {
    // ...
}
else {
    // ...
}

If you use std::string (which is advisable), the code would be similar, except that you can use == rather than strcmp.

You could set up a data structure that lets compute a discrete value that you can then use in a switch/case statement, as R Sahu's answer suggests. This would save the overhead of potentially doing N string comparisons. In my opinion, that would be overkill for a simple case like this. If your actual code is larger and more complex, it's worth considering.

Or you might consider redesigning your data structure so that you store and test an enumeration value directly, and then get a string value from that enumeration value via a lookup table.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Remy Lebeau
Solution 2 James Curran
Solution 3 Richard Hodges
Solution 4 Community