2013-03-03 14 views
8

Kilka razy w moim programie musiałem sprawdzić, czy zmienna była jedną z wielu opcji. Na przykład:C++ Najskuteczniejszy sposób porównania zmiennej z wieloma wartościami?

if (num = (<1 or 2 or 3>)) { DO STUFF } 

Połączyłem z "OR", ale nic nie wydaje się być w porządku. Próbowałem już próbować:

if (num == (1 || 2 || 3)) 

ale to nic nie robi. Proszę pomóż! Z góry dzięki.

P.S. Muszę rozróżnić kilka grup. Na przykład ...

if (num = (1,2,3)) 

else if (num = (4,5,6)) 

else if (num = (7,8,9)) 
+2

jest 'if (Lb == 1 || num == 2 || num == 3) 'lub' if (numer> = 1 && num < 3) "za dużo pisania? Jeśli jest dłuższy, zawsze możesz utworzyć tablicę i użyć 'std :: find'. – chris

+1

Zobacz http://stackoverflow.com/q/14368525/726361 –

+0

Dzięki za szybkie odpowiedzi. @ Chris, szukałem czegoś bardziej eleganckiego. –

Odpowiedz

6

przypadku wartości ty chcesz sprawdzić są wystarczająco małe, możesz utworzyć maskę wartości, których szukasz, a następnie sprawdź, czy bit jest ustawiony.

Załóżmy, że zależy Ci na kilku grupach.

static const unsigned values_group_1 = (1 << 1) | (1 << 2) | (1 << 3); 
static const unsigned values_group_2 = (1 << 4) | (1 << 5) | (1 << 6); 
static const unsigned values_group_3 = (1 << 7) | (1 << 8) | (1 << 9);  
if ((1 << value_to_check) & values_group_1) { 
    // You found a match for group 1 
} 
if ((1 << value_to_check) & values_group_2) { 
    // You found a match for group 2 
} 
if ((1 << value_to_check) & values_group_3) { 
    // You found a match for group 3 
} 

To podejście sprawdza się najlepiej w przypadku wartości, które nie przekraczają naturalnej wielkości, z jaką CPU lubi pracować. Zazwyczaj będzie to 64 w czasach współczesnych, ale może się różnić w zależności od specyfiki środowiska.

+0

Cool. To czyni sprawę łatwą. Jeśli chciałem zobaczyć "jeśli 1, inaczej jeśli 2, inaczej jeśli 3;" jak bym to zrobił? Czy potrzebowałbym nowej maski bitowej, czy też mógłbym dodać "(2 << n)"? –

+0

Jeśli chcesz sprawdzić wartości 1, 2 i 3, to twoja maska ​​bitowa stanie się tym zamiast wartości_i_like = (1 << 1) | (1 << 2) | (1 << 3); –

+0

nie, źle rozumiesz. Chcę móc różnić się od (1,2,3) i (4,5,6) –

4

Musisz wykonać porównanie z każdą wartością. Na przykład.

if (num == 1 || num == 2 || num == 3) { stuff } 

Można również rozważyć przełącznik i celowo przez wypadnięcie przypadków (choć nie sądzę, że jest to najlepsze rozwiązanie dla czego stwierdzając).

switch (num) { 
    case 1: 
    case 2: 
    case 3: 
     {DO STUFF} 
     break; 

    default: 
     //do nothing. 
} 
+0

Tak, nie dokładnie to, czego szukam. W każdym razie dzięki! –

+1

Umm, nie, nie możesz tego zrobić. – einpoklum

2

Można zdefiniować zbiór liczb całkowitych, dodać żądane wartości do niego, a następnie użyć metody find, aby sprawdzić, czy wartość w pytaniu jest w zestawie

std::set<int> values; 
// add the desired values to your set... 
if (values.find(target) != values.end()) 
    ... 
+0

To interesujący sposób robienia rzeczy ... Spróbuję, dzięki! –

+0

Przepraszam, dostaję tonę błędów. Jak dokładnie używasz tego? Czy mógłbyś podać przykład? –

+2

lol, geniusz w swojej prostocie! @ TheWalkingCactus po prostu użyj 'count' zamiast' set'. –

14

Oto sposób w C++ 11, za pomocą std :: initializer_list:

#include <initializer_list> 

template <typename T> 
bool is_in(const T& val, const std::initializer_list<T>& list) 
{ 
    for (const auto& i : list) { 
     if (val == i) { 
      return true; 
     } 
    } 
    return false; 
} 

z tym, można zrobić:

if (is_in(num, {1, 2, 3}) { DO STUFF } 

Należy jednak pamiętać, że takie rzeczy jak <1 nie są możliwe.

+0

To wygląda wygodnie, ale nie używam 11. Jestem po prostu w prostym C++. –

3

prostu miałem podobny problem i doszedłem do tych rozwiązań C++ 11:

template <class T> 
struct Is 
{ 
    T d_; 
    bool in(T a) { 
    return a == d_; 
    } 
    template <class Arg, class... Args> 
    bool in(Arg a, Args... args) { 
    return in(a) || in(args...); 
    } 
}; 

template <class T> 
Is<T> is(T d) { 
    return Is<T>{d}; 
} 

Albo jako alternatywa bez sposobie zakończenia rekurencji. Pamiętaj, że kolejność porównań jest niezdefiniowana i nie kończy się ona wcześniej, jeśli zostanie znaleziony pierwszy mecz. Ale kod jest bardziej zwarty.

template <class T> 
struct Is { 
    const T d_; 
    template <class... Args> 
    bool in(Args... args) { 
    bool r{ false }; 
    [&r](...){}(((r = r || d_ == args), 1)...); 
    return r; 
    } 
}; 

template <class T> 
Is<T> is(T d) { 
    return Is<T>{d}; 
} 

Więc dla obu rozwiązań kod wyglądałby następująco:

if (is(num).in(1,2,3)) { 
    // do whatever needs to be done 
} 
0

muszę zrobić coś podobnego na teksty stałe. Mam zmienną i chcę przetestować ją na zakresach wartości.

Tutaj użyłem funkcji szablonu variadic. Zwróć uwagę na specjalizację dla typu const char*, dzięki czemu is_in(my_str, "a", "b", "c") ma oczekiwany rezultat, gdy my_str przechowuje.

#include <cstring> 

template<typename T> 
constexpr bool is_in(T t, T v) { 
    return t == v; 
} 

template<> 
constexpr bool is_in(const char* t, const char* v) { 
    return std::strcmp(t,v); 
} 

template<typename T, typename... Args> 
constexpr bool is_in(T t, T v, Args... args) { 
    return t==v || is_in(t,args...); 
} 

Przykład użycia:

enum class day 
{ 
    mon, tues, wed, thur, fri, sat, sun 
}; 

bool is_weekend(day d) 
{ 
    return is_in(d, day::sat, day::sun); 
} 
Powiązane problemy