views:

94

answers:

4

Say I have a class "Code" defined like this, with a user specified type conversion to int:

class Code
{
public:    
    int code;
    std::string description;

    Code (const int c, const std::string& d) : code(c), description(d) { ; }

    operator int() const { return code; }
};

And a second class "Master" using the code class:

class Master
{
public:
    Code master_code;
};

As well as a bunch of pre-specified codes, like this:

const Code CODE_ONE    (1, "This is code one");
const Code CODE_TWO    (2, "This is code two");
const Code CODE_THREE  (3, "This is code three");

One would think (i.e. I would think) that one could use it like this:

Master master_obj;
switch (master_obj.master_code)
{
    case CODE_ONE:
        // ...
        break;

    case CODE_TWO:
        // ...
        break;

    case CODE_THREE:
        // ...
        break;

    default:
        // ...
}

due to the automatic type conversion to int, but this is apparently not the case. GCC tells me that CODE_ONE, CODE_TWO and CODE_THREE "can not appear in a constant-expression".

This does not work either, by the way:

Master master_obj;
switch (master_obj.master_code)
{
    case CODE_ONE.code:
        // ...
        break;

    case CODE_TWO.code:
        // ...
        break;

    case CODE_THREE.code:
        // ...
        break;

    default:
        // ...
}

The above returns the exact same error: "'CODE_ONE' can not appear in a constant-expression" in addition to a "'.' can not appear in a constant-expression".

But this does work:

Master master_obj;
switch (master_obj.master_code)
{
    case 1:
        // ...
        break;

    case 2:
        // ...
        break;

    case 3:
        // ...
        break;

    default:
        // ...
}

So CODE_ONE etc. can't be resolved as constant expressions? That seems weird... Or am I doing something wrong?

+5  A: 

The labels in a switch statement must be "integral constant-expressions" (§6.4.2/2). An integral constant expression" is defined as (§5.19/1):

An integral constant-expression can involve only literals (2.13), enumerators, const variables or static data members of integral or enumeration types initialized with constant expressions (8.5), non-type template parameters of integral or enumeration types, and sizeof expressions. Floating literals (2.13.3) can appear only if they are cast to integral or enumeration types. Only type conversions to integral or enumeration types can be used. In particular, except in sizeof expressions, functions, class objects, pointers, or references shall not be used, and assignment, increment, decrement, function-call, or comma operators shall not be used.

So, you can't have a function call (including a conversion function), and a data member must be static (which yours isn't).

Jerry Coffin
Oh bum. Well, thanks for clarifying then.
oystein
@oystein: I should probably add that C++0x does expand the idea of constant expressions a bit. It adds `constexpr`, which you can use to mark things as constant expressions, so with something like `int constexpr f() { return 1; }` you can use `f()` as a constant expression.
Jerry Coffin
A: 

Case labels of a switch case statements should be compile time constants and shall be integral. CODE_ONE, CODE_TWO etc are not compile time integral constants.

Refer 6.4.2/2

Chubsdad
+1  A: 

The switch labels must be compile-time constants. The values you want to compare aren't available until after the CODE_XXX objects have been created at runtime.

Mike Seymour
A: 

The fact that CODE_ONE, ... etc are defined as const does not mean they are actually constant expressions. All const does is 'try' and enforce that those class instances do not change by const defined rules. In the end a class(or struct for that matter) instance is never considered a fully constant expression since it is a dynamic object.

What a switch statement needs is a "compile-time constant expression" which for all intents and purposes regarding C++98 is an int literal or an enum value(also int literal in the end).

C++0x' constexpr will let you do more complex things like use constant functions, but not what you are asking for.

Ramon Zarazua