tags:

views:

555

answers:

5

Ok, I'm new at C++. I got Bjarne's book, and I'm trying to follow the calculator code.

However, the compiler is spitting out an error about this section:

token_value get_token()
{
    char ch;

    do {        // skip whitespace except '\n'
        if(!std::cin.get(ch)) return curr_tok = END;
    } while (ch!='\n' && isspace(ch));

    switch (ch) {
        case ';':
        case '\n':
            std::cin >> WS;      // skip whitespace
            return curr_tok=PRINT;
        case '*':
        case '/':
        case '+':
        case '-':
        case '(':
        case ')':
        case '=':
            return curr_tok=ch;
        case '0': case '1': case '2': case '3': case '4': case '5':
        case '6': case '7': case '8': case '9': case '.':
            std::cin.putback(ch);
            std::cin >> number_value;
            return curr_tok=NUMBER;
        default:            // NAME, NAME=, or error
            if (isalpha(ch)) {
                char* p = name_string;
                *p++ = ch;
                while (std::cin.get(ch) && isalnum(ch)) *p++ = ch;
                std::cin.putback(ch);
                *p = 0;
                return curr_tok=NAME;
            }
            error("bad token");
            return curr_tok=PRINT;
}

The error it's spitting out is this:

calc.cpp:42: error: invalid conversion from ‘char’ to ‘token_value’

token_value is an enum that looks like:

enum token_value {
    NAME,       NUMBER,     END,
    PLUS='+',   MINUS='-',  MUL='*',  DIV='/',
    PRINT=';',  ASSIGN='=', LP='(',   RP=')'
};
token_value curr_tok;

My question is, how do I convert ch (from cin), to the associated enum value?

+2  A: 

You can't implicitly cast from char to an enum - you have to do it explicitly:

return curr_tok = static_cast<token_value> (ch);

But be careful! If none of your enum values match your char, then it'll be hard to use the result :)

Jesse Beder
+1  A: 

You need an explicit cast:

curr_tok = static_cast<token_value>(ch);

The reason is that it's dangerous to convert an integer type to an enum. If the value is not valid for the enum then behaviour is undefined. So the language doesn't let you do it accidentally with an implicit conversion. The explicit conversion is supposed to mean "I know what I'm doing, and I've checked that the value is valid".

Steve Jessop
A: 
return curr_tok=(token_value)ch;
Keith Nicholas
Prefer to use new-style casts (i.e. `static_cast` etc.) when using C++ instead of C.
ChrisW
Or if you do want to use C-style casts, sneak them under the radar using the constructor syntax: `curr_tok = token_value(ch)`. The author of your style guide might think twice before banning single-argument constructors, even though they can only be invoked using a C-style cast. ;-)
Steve Jessop
+2  A: 

Note that the solutions given (i.e. telling you to use a static_cast) work correctly only because when the enum symbols were defined, the symbols (e.g. PLUS) were defined to have a physical/numeric value which happens to be equal to the underlying character value (e.g. '+').

Another way (without using a cast) would be to use the switch/case statements to specify explicitly the enum value returned for each character value, e.g.:

    case '*':
      return curr_tok=MUL;
    case '/':
      return curr_tok=DIV;
ChrisW
A: 

I think I wouldn't try to explicitly set the values of the enum symbols and instead write a case for every symbol that in your switch statement. Doing it that way will probably be harder to debug if something goes wrong and the performance cost writing a case for every symbol is so low, that it's not even worth considering (unless you're writing for some kind of extremely low-end embedded system and probably still not worth it).

Jonathan Swinney