2016-02-29 2 views
2

Я нашел фрагмент кода в Интернете, который имеет очень простую цель, но он использует уродливый подход. Предположительно, автор использует случай переключения, чтобы определить, принадлежат ли некоторые (несмежные) значения ранее определенного Enum в своей области. Если это так, функция возвращает true и все. Else, он возвращает false.Избегайте повторения и простого случая переключения в C/C++?

Это практически выглядит следующим образом:

switch(value) { 
case ONE: 
case TWO: 
/* many similar lines later */ 
case TWENTY: 
case TWENTY_FIVE: 
/* an afternoon later */ 
case ONE_HUNDRED: 
    return true; 
default: 
    return false; 
} 

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

Я читал о функции вложения и использовании массива указателей функций, но я не знаю, как использовать это в таком конкретном случае.

Как избежать написания множества строк case X: с таким простым случаем (без каламбура), как это?

+2

Полностью длинный оператор 'switch' и/или' if' обычно является признаком плохого использования OOP – hgiesel

+2

@henrikgiesel, откуда появился ООП? – SergeyA

+1

В чем ваш вопрос? Я не понимаю. –

ответ

3

Избегайте повторения и простого случая переключения в C/C++?

Да, не избежать этого .. Вы должны нормально работать на самом высоком уровне абстракции возможно в любой заданной области/контекста, является ли время компиляции полиморфизм (например, с использованием шаблонов), объектно-ориентированное программирование или, простые структуры управления .. Во-первых пришли правильность, ясность коды и эффективность, а затем идет оптимизацию (и только после правильного измерения)

В данном конкретном случае вы можете просто сделать это:

return (value < 100); 

Я не вижу почему более эффективный оператор переключения на 100+ строк, даже если это быстрее (это просто предположение при отсутствии фактических измерений), это будет только немного быстрее в любом случае, так ли это заслуживает всей этой суеты ?? Нет, или, по крайней мере, нет в большинстве сценариев реальной жизни. Если приложение является критическим, оптимизация такого кода лучше всего выполняется на языке ассемблера.

Что касается функции inlining и массивов указателей функций - I ' я не уверен, что понимаю, что такое вопросы, но тем не менее, если вы не понимаете, как использовать такие функции для оптимизации, не используйте их. пусть компилятор оптимизирует ваш код.

+1

Не будучи экспертом по C/C++, почему оператор 'switch' будет быстрее? По моему мнению, он должен сравнивать «значение» 100 раз, а 'if' делает это только один раз. – sjaustirni

+3

Определенно 'возвращаемое значение <100;' пожалуйста ... – Barry

+0

действительно .. Я отредактирую это. –

0

Поскольку у вас есть нечетное перечисление, пропуская значения, вы можете инвертировать свое решение. Но вам нужно будет объявить пропущенные номера (если он пропускает только несколько).

if(value > ONE_HUNDRED || value < ONE) 
{ 
    return false; 
} 
else 
{ 
    switch(value) 
    { 
     case SKIPPED_FIRST: 
     case SKIPPED_SECOND: 
     { 
      return false; 
     } 
     break; 
     default: 
     { 
      return true; 
     } 
    } 
} 
+0

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

+0

Вы забыли ключевое слово 'case': Синтаксическая ошибка. – abelenky

+0

никаких проблем, просто не мог предположить, что в комментарии –

9

Вычислительный логическое значение эффективно, основываясь на некотором связанные целом числе является работой для операций с битами:

const unsigned long long ps[2] = {0x28208a20a08a28ac, 0x800228a202088288}; 

bool is_prime(unsigned x) 
{ 
    return (x < 128) && ((ps[x >> 6] >> (x & 63)) & 1); 
} 

Если посмотреть на двоичном представлении чисел, хранящихся в массиве, 1 бит означает простое число, и 0 бит означает количество соединения:

2 8 2 0 8 a 2 0 a 0 8 a 2 8 a c 
0010 1000 0010 0000 1000 1010 0010 0000 1010 0000 1000 1010 0010 1000 1010 1100 
    59    47  41   31  23  17  11  5 2 
61  53   43  37  29   19  13  7 3 

для масштабирования это более чем 128 номеров, просто увеличить размер массива и залатать < сравнение в is_prime. Константы 6 и 63 основываются на количестве бит в unsigned long long.

+3

Но бит спрятался страшно:/ – SolaGratia

+0

Случалось ли вам помнить '0x28208a20a08a28ac' для этого использования? , поэтому бит twiddling требует запоминания/копирования папок шестнадцатеричных чисел? –

+1

@AngelusMortis Нет, я написал [программу] (http://chat.stackoverflow.com/transcript/message/29044107#29044107), чтобы сгенерировать номер. – fredoverflow