Ожидаемое константное выражение с треском проваливается в операторе switch - PullRequest
2 голосов
/ 13 августа 2010

Скажем, у меня есть класс "Код", определенный следующим образом, с указанным пользователем преобразованием типа в 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; }
};

И второй класс "Мастер", использующий класс кода:

class Master
{
public:
    Code master_code;
};

Так же, как и набор заранее заданных кодов, например:

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");

Можно подумать (то есть, я бы подумал), что можно использовать его так:

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

    case CODE_TWO:
        // ...
        break;

    case CODE_THREE:
        // ...
        break;

    default:
        // ...
}

из-за автоматического преобразования типов в int, но это, очевидно, не так.GCC сообщает мне, что CODE_ONE, CODE_TWO и CODE_THREE "не могут появляться в выражении-константе".

Кстати, это тоже не работает:

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

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

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

    default:
        // ...
}

Выше приведено точноета же ошибка: «CODE_ONE» не может появляться в константном выражении »в дополнение к« ».не может отображаться в константном выражении ".

Но это работает:

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

    case 2:
        // ...
        break;

    case 3:
        // ...
        break;

    default:
        // ...
}

То есть CODE_ONE и т. д. не могут быть разрешены как константные выражения?Это кажется странным ... Или я делаю что-то не так?

Ответы [ 4 ]

6 голосов
/ 13 августа 2010

Метки в выражении switch должны быть «целочисленными константами-выражениями» (§6.4.2 / 2). Целочисленное постоянное выражение "определяется как (§5.19 / 1):

Интегральное выражение-константа может включать только литералы (2.13), перечислители, константные переменные или члены-статические данные целочисленных или перечислимых типов, инициализированных константными выражениями (8.5), нетиповые шаблонные параметры целочисленных или перечислимых типов и sizeof выражения. Плавающие литералы (2.13.3) могут появляться, только если они приводятся к целочисленным или перечислимым типам. Можно использовать только преобразования типов в целочисленные или перечислимые типы. В частности, за исключением выражений sizeof, функции, объекты классов, указатели или ссылки не должны использоваться, а операторы присваивания, приращения, уменьшения, вызова функции или запятой не должны использоваться.

Таким образом, у вас не может быть вызова функции (включая функцию преобразования), и элемент данных должен быть статическим (а у вас нет).

1 голос
/ 13 августа 2010

Метки переключателей должны быть константами времени компиляции. Значения, которые вы хотите сравнить, недоступны до тех пор, пока объекты CODE_XXX не будут созданы во время выполнения.

0 голосов
/ 13 августа 2010

Тот факт, что CODE_ONE, ... и т. Д. Определены как const, не означает, что они на самом деле являются константными выражениями.Все, что делает const, это «пробует» и заставляет эти экземпляры классов не изменяться по определенным правилам const.В конце концов, экземпляр класса (или структуры в этом отношении) никогда не считается полностью константным выражением, поскольку он является динамическим объектом.

В операторе switch требуется «постоянное выражение времени компиляции», которое для всехнамерения и цели, касающиеся C ++ 98, являются литералом int или значением enum (в конце также является литералом int).

C ++ 0x 'constexpr позволит вам делать более сложные вещинравится использовать постоянные функции, но не то, что вы просите.

0 голосов
/ 13 августа 2010

Метки случая операторов регистра переключателя должны быть постоянными времени компиляции и должны быть целыми. CODE_ONE, CODE_TWO и т. Д. Не являются интегральными постоянными времени компиляции.

См. 6.4.2 / 2

...