2013-08-02 2 views
2

Я кодирую в C++ для Nintendo DS, но это должно быть универсальным со всеми C++.Более эффективный способ кодирования if then else в C++

Я уже знаю о заявлениях коммутатора, но мне нужно сделать набор, если, то, и другое, что есть несколько аргументы:

void doSomething(int number) 
{ 
... 
} 

bool left = true; 
bool right = false; 
bool top = false; 
bool bottom = false; 

if (left && top && right) 
    doSomething(1); 
else if (top && right && bottom) 
    doSomething(2); 
else if (left && right && bottom) 
    doSomething(3); 
else if (left && top && bottom) 
    doSomething(4); 

Любая помощь приветствуется.

+0

Если только один из этих булевы будет верно, вы могли бы выполнить четыре последовательных оператора 'if', и им не нужно было встраиваться.Например, 'if (left) doSomething (1); if (right) doSomething (2); 'и т. д. – Xynariz

+2

Что определяет ценности вашего bool? Ваши тесты кажутся необычными. Как могли быть прав и левые и правые? Объяснение того, что означают эти переменные, может помочь. –

+0

Я нахожу идею, например, Правая граница представлена ​​слева, сверху и снизу, причем все это очень противоречиво. –

ответ

10

Вы можете преобразовать четыре булевы в виде двоичного числа 0..15, и использовать массив для поиска параметров, например:

int location = (left ? 1<<0 : 0) 
      | (right ? 1<<1 : 0) 
      | (top ? 1<<2 : 0) 
      | (bottom ? 1<<3 : 0); 

Теперь location имеет число от 0 до 15, так вы можете сделать это:

int lookup[] = {-1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 3, -1, 4, 2, -1}; 
int arg = lookup[location]; 
if (arg != -1) { 
    doSomething(arg); 
} 
+1

Вы можете выполнить поиск массива const. –

+1

Предположим, что я вернулся шесть месяцев спустя и попытаюсь понять, что делает этот кусок кода, не лучше ли мне с исходной версией кода? Я действительно не понимаю, как этот ответ улучшает что-либо. Пожалуйста, объясните, может быть, я что-то упустил ... – Tarik

+0

Неужели это так плохо? Выглядит довольно просто ... Тройные операторы могут быть немного, но meh. Хотя теперь 'doSomething()' потребуется инструкция switch между разными значениями аргументов. – Suedocode

0

Инкапсулируйте это в getSide(), который возвращает перечисление. Я полагаю, что логические переменные доступны из класса реализации или вызова DoSomething

... 
    bool left = true; 
    bool right = false; 
    bool top = false; 
    bool bottom = false; 
    ... 
    doSomething(getSide()); 
    ... 

    enum Side { 
    Top, Bottom, Left, Right 
    } 

    void doSomething(Side side) 
    { 
    ... 
    } 

    Side getSide() { 
    if (left && top && right) //Bottom Border 
     return Side.Bottom; 
    else if (top && right && bottom) //Left Border 
     return Side.Left; 
    else if (left && right && bottom) //Top Border 
     return Side.Top; 
    else if (left && top && bottom) //Right Border 
     return Side.Right; 
    } 
+0

Хотя это сработает, оно не избегает использования if ... else, если –

+0

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

1

Если вы действительно псих (или обфускатор), вы могли бы использовать что-то вроде битовых масок:

unsigned char direction = 8; // 1 0 0 0 for l r t b 

или, оставаясь в соответствии с конвенцией вы использовали в вашем вопросе:

unsigned char direction = left + (right << 1) + (top << 2) + (bottom << 3); 

и тогда вы будете иметь (*):

switch(direction) { 
    case 14: // 1 1 1 0 
     doSomething(1); 
     break; 
    case 7: // 0 1 1 1 
     doSomething(2); 
     break; 
    case 13: // 1 1 0 1 
     doSomething(3); 
     break; 
    case 11: // 1 0 1 1 
     doSomething(4); 
     break; 
} 

И если вам нужно получить доступ к индивидуальной стоимости удобно:

inline bool left() {return (direction & 8) == 8;} 
inline bool right() {return (direction & 4) == 4;} 
inline bool top() {return (direction & 2) == 2;} 
inline bool bottom() {return (direction & 1) == 1;} 

Вообще-то, это должно быть довольно быстро ...


(*) В качестве альтернативы , вы также можете написать:

const unsigned char left_c = 8; 
const unsigned char right_c = 4; 
const unsigned char top_c = 2; 
const unsigned char bottom_c = 1; 

и проверить комбинацию, как это (постоянного выражения принимается в коммутаторах):

switch(direction) { 
    case (left_c + right_c + top_c): 
     doSomething(1); 
     break; 
    ... 
} 
0

Я добавляю этот ответ, чтобы показать, как можно std::bitset может быть использовано для этой цели. Я знаю, что, возможно, ваша целевая платформа не будет поддерживать стандарт C++ 11, но, надеюсь, это может помочь кому-то другому.

#include<iostream> 
#include<bitset> 
#include<vector> 
#include<map> 

// The location is represented as a set of four bits; we also need a 
// comparator so that we can later store them in a map. 
using Location = std::bitset<4>; 
struct LocationComparator { 
    bool operator()(const Location& loc1, const Location& loc2) const { 
    return loc1.to_ulong() < loc2.to_ulong(); 
    } 
}; 

// the callback (handler) has a signature "void callback()" 
using Callback = void (*)(); 

// the mapping between location and callback is stored in a simple 
// std::map 
using CallbackMap = std::map<Location, Callback, LocationComparator>; 

// we define the fundamental locations 
const Location Top ("1000"); 
const Location Bottom("0100"); 
const Location Right ("0010"); 
const Location Left ("0001"); 

// ... and define some actions (notice the signature corresponds to 
// Callback) 
void action_1() { std::cout<<"action 1"<<std::endl;} 
void action_2() { std::cout<<"action 2"<<std::endl;} 
void action_3() { std::cout<<"action 3"<<std::endl;} 
void action_4() { std::cout<<"action 4"<<std::endl;} 

// ... now create the map between specific locations and actions 
// (notice that bitset can perform logical operations) 
CallbackMap callbacks = { 
    { Top | Right , action_1 }, 
    { Top | Left , action_2 }, 
    { Bottom | Right , action_3 }, 
    { Bottom | Left , action_4 }, 
}; 

// an abstract game element has a location, the interaction will 
// depend on the defined callbacks 
class GameElement { 
public: 
    GameElement(const Location& location) 
     : m_location(location) { } 

    void interact() const { 
    callbacks[m_location](); 
    } 

    virtual ~GameElement() { } // so that others can inherit 
private: 
    Location m_location; 
}; 

int main() { 
    // create a vector of game elements and make them interact according 
    // to their positions 

    std::vector<GameElement> elements; 

    elements.emplace_back(Top | Right); 
    elements.emplace_back(Top | Left); 
    elements.emplace_back(Bottom | Right); 
    elements.emplace_back(Bottom | Left); 

    for(auto & e : elements) { 
    e.interact(); 
    } 

} 

Я собирал его на OS X с помощью GCC 4.7.2 с помощью следующей команды:

g++ locations.cpp -std=c++11 

Выход есть:

action 1 
action 2 
action 3 
action 4 
Смежные вопросы