Использование элементов постоянного массива в качестве случаев в выражении switch - PullRequest
6 голосов
/ 15 декабря 2008

Я пытаюсь сопоставить набор нажатий клавиш с набором команд. Поскольку я обрабатываю команды из нескольких мест, я хотел бы установить уровень абстракции между ключами и командами, чтобы при изменении основных сопоставлений клавиш мне не пришлось сильно менять код. Моя текущая попытка выглядит так:

// input.h
enum LOGICAL_KEYS {
    DO_SOMETHING_KEY,
    DO_SOMETHING_ELSE_KEY,
    ...
    countof_LOGICAL_KEYS
};

static const SDLKey LogicalMappings[countof_LOGICAL_KEYS] = {
    SDLK_RETURN,    // Do Something
    SDLK_ESCAPE,    // Do Something Else
    ...
};

// some_other_file.cpp
...
switch( event.key.keysym.key ) {
    case LogicalMappings[ DO_SOMETHING_KEY ]:
        doSomething();
        break;
    case LogicalMappings[ DO_SOMETHING_ELSE_KEY ]:
        doSomethingElse();
        break;
    ...
}

Когда я пытаюсь скомпилировать это (gcc 4.3.2), я получаю сообщение об ошибке:

ошибка: «LogicalMappings» не может появляться в константном выражении

Я не понимаю, почему у компилятора такая проблема. Я понимаю, почему вы не можете иметь переменные в выражении case, но у меня сложилось впечатление, что вы можете использовать константы, поскольку они могут быть оценены во время компиляции. Не работают ли константы с операторами switch? Если это так, я полагаю, я мог бы просто заменить массив на что-то вроде:

static const SDLKey LOGICAL_MAPPING_DO_SOMETHING      = SDLK_RETURN;
static const SDLKey LOGICAL_MAPPING_DO_SOMETHING_ELSE = SDLK_ESCAPE;
...

Но это выглядит гораздо менее элегантно. Кто-нибудь знает, почему здесь нельзя использовать константный массив?

РЕДАКТИРОВАТЬ: Я видел немного стандарта C ++, который утверждает, что «Интегральное выражение-константа может включать только литералы (2.13), перечислители, константные переменные или члены-статические данные целочисленных или перечислимых типов, инициализированных с помощью константных выражений. (8,5) ... ". Я до сих пор не понимаю, почему константный массив не считается «типом перечисления, инициализированным константным выражением». Может быть так, что ответ на мой вопрос «потому что так оно и есть», и мне придется обойти это. Но если это так, то это разочаровывает, потому что компилятор действительно может определить эти значения во время компиляции.

Ответы [ 7 ]

3 голосов
/ 15 декабря 2008

Ссылаясь на разделы стандарта C ++: 6.4.2 требует, чтобы выражения регистра оценивались как интеграл или константа перечисления. 5.19 определяет, что это такое:

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

Так что, если ваш вопрос был «почему компилятор отклоняет это», один ответ - «потому что так говорит стандарт».

2 голосов
/ 15 декабря 2008

Ссылки на массивы не являются «достаточно постоянными», независимо от того.

Вам просто нужно сделать отображение немного по-другому. Вы хотите, чтобы то же действие происходило при нажатии логической клавиши, поэтому используйте коды логической клавиши в предложениях case оператора switch. Затем сопоставьте действительный код ключа с логическим кодом, возможно, в самом switch или, возможно, заранее. Вы все еще можете использовать массив LogicalMappings или аналогичную конструкцию. И, в качестве помощи G11N (глобализация), вы даже можете сделать массив отображений непостоянным, чтобы разные люди могли переназначать ключи в соответствии со своими потребностями.

1 голос
/ 15 декабря 2008

Я остановлюсь здесь на вопросе, поскольку никто больше не ответил на это, и я в основном недавно занимался Java, а не C ++, но, насколько я помню, поиск в массиве не считается постоянным целым числом, даже если Результат поиска может быть определен во время компиляции. Это может даже быть проблемой в синтаксисе.

0 голосов
/ 17 декабря 2008

Гуру-компилятор на работе объяснил мне это. Проблема в том, что сам массив является постоянным, но индексы к нему не обязательно являются постоянными. Таким образом, выражение LogicalMappings [some_variable] не может быть оценено во время компиляции, поэтому массив все равно хранится в памяти, а не компилируется. До сих пор нет причин, по которым компилятор не мог бы статически оценивать ссылки на массивы с помощью константного или литерального индекса, поэтому теоретически возможно, что я хочу сделать, но это немного сложнее, чем я думал, поэтому я могу понять, почему gcc не не делай этого.

0 голосов
/ 15 декабря 2008

Вы также можете использовать массив указателей на функции или функторов (я полагаю, адреса функторов), чтобы вообще избежать оператора switch и просто перейти из индекса массива -> указатель / функтор функции напрямую.

например (предупреждение, непроверенный код следует)

class Event // you probably have this defined already
{
}

class EventHandler // abstract base class
{
public:
  virtual void operator()(Event& e) = 0;
};

class EventHandler1
{
  virtual void operator()(Event& e){
    // do something here 
  }
};
class EventHandler2
{
  virtual void operator()(Event& e){
    // do something here 
  }
};

EventHandler1 ev1;
EventHandler2 ev2;
EventHandler *LogicalMappings[countof_LOGICAL_KEYS] = {
  &ev1,
  &ev2,
  // more here...

};

// time to use code:
Event event;
if (event.key.keysym.key < countof_LOGICAL_KEYS)
{
   EventHandler *p = LogicalMappings[event.key.keysym.key];
   if (p != NULL)
      (*p)(event);
}
0 голосов
/ 15 декабря 2008

Существует библиотека с именем signal в ускорении, которая поможет вам создать абстракцию отображения событий. Если у вас есть время, подход лучше

0 голосов
/ 15 декабря 2008

Определен ли оператор сравнения для "LogicalMappings"? Если нет, то это ошибка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...