6

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?

Ono
  • 1,357
  • 3
  • 16
  • 38
  • 2
    switch can only be used with integer values. You are giving it a pointer to char. – Beed Dec 17 '14 at 23:17
  • `atof(name)` should be `atof(value)` instead. – Remy Lebeau Dec 17 '14 at 23:29
  • `'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 use by mistake more often than correctly. (String literals use double quotes; character literals use single quotes). You *can't* do a `switch/case` on a `char*`. – Keith Thompson Dec 17 '14 at 23:37
  • @RemyLebeau Yes you are right. Changed and thanks! – Ono Dec 18 '14 at 14:06

5 Answers5

16

You cannot use switch here; as the error says, const char* is not supported. It's a good thing, too, because comparing two C-strings through pointers only compares the pointers, not the strings they point to (consider "hello" == "world").

Even if it were, you're trying to compare your C-string to multicharacter literals, which is certainly not what you intended, not least of all because they have type int and an implementation-defined value; I guess you meant to write "SRAD", not 'SRAD'.

Since you're using C++, you should do this:

const std::string name = pAttr->Name();
const std::string value = pAttr->Value();

if (name == "SRAD") {
   double D = atof(value.c_str());  // use std::stod(value) in C++11
   // ...
}
else if (name == "DRAD") {
   // ...
}
else {
   // ...
}

(I also fixed your use of name in the initialisation of D; Remy's right — you must have meant value here since "SRAD" cannot possibly be interpreted as a double.)

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
5

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;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • 2
    This is good, except that `localMap[name]` will return 0 if `name` is not found, and you have defined 0 as `SRAD`. It would be better to start the enum values at 1 instead, so you can handle 0 for unknown names. Also, `atof(name)` should be `atof(value)` instead, that is a typo in the OP's code. `atof("SRAD")` will always fail. – Remy Lebeau Dec 17 '14 at 23:27
  • 3
    Seems correct, but you pay the cost of map indexing complexity. Why not using an if-else conditional statement? – Nick Louloudakis Dec 17 '14 at 23:27
  • 1
    @NickL., it will be interesting to see the relative costs of the two approaches with a small `map`. – R Sahu Dec 17 '14 at 23:33
4

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).

James Curran
  • 101,701
  • 37
  • 181
  • 258
1

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;
}
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
-1

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.

Community
  • 1
  • 1
Keith Thompson
  • 254,901
  • 44
  • 429
  • 631