как определить, является ли значение класса enum в указанном диапазоне класса enum более эффективным способом? [Дубликат]

Еще один способ сделать это:

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;

template <typename T>
string join(const T& v, const string& delim) {
    ostringstream s;
    for (const auto& i : v) {
        if (&i != &v[0]) {
            s << delim;
        }
        s << i;
    }
    return s.str();
}

int main() {
    cout << join(vector<int>({1, 2, 3, 4, 5}), ",") << endl;
}

(c ++ 11 для цикла и «авто»)

9
задан Rakete1111 5 July 2016 в 01:50
поделиться

6 ответов

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

Предположим, вы заботитесь о паре групп.

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
}

Этот подход лучше всего подходит для значений, которые не превышают естественный размер, с которым вам нравится работать процессор. Обычно это будет 64 в наше время, но может варьироваться в зависимости от специфики вашей среды.

9
ответ дан Eric Johnson 15 August 2018 в 23:35
поделиться
  • 1
    Круто. Это упрощает дело. Если бы я хотел увидеть «если 1; else if 2, else if 3; & quot; как бы я это сделал? Мне нужна новая битовая маска, или я могу просто добавить в & quot; (2 & lt; n) "? – Matthew Reynolds 3 March 2013 в 14:37
  • 2
    Если вы хотите проверить значения 1, 2 и 3, тогда ваша битовая маска станет таковой вместо values_i_like = (1 & lt; 1) | (1 & lt; 2) | (1 & л; & л; 3) ;. – Eric Johnson 3 March 2013 в 14:48
  • 3
    нет, вы неправильно понимаете. Я хочу иметь возможность отличаться от (1,2,3) и (4,5,6) – Matthew Reynolds 3 March 2013 в 14:51
  • 4
    values_i_like = (1 & lt; 1) | (1 & lt; 2) | (1 & lt; 3) | (1 & lt; 4) | (1 & lt; 5) | (1 & Lt; & Lt; 6); – Eric Johnson 3 March 2013 в 14:54
  • 5
    но как бы вы отличались от (1,2,3) и (4,5,6)? – Matthew Reynolds 3 March 2013 в 14:55

Мне нужно было сделать что-то подобное для перечислений. Я имею переменную и хочу ее протестировать против диапазонов значений.

Здесь я использовал вариационную функцию шаблона. Обратите внимание на специализацию для типа const char*, так что is_in( my_str, "a", "b", "c") имеет ожидаемый результат, когда my_str сохраняет "a".

#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...);
}

Пример использования:

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

bool is_weekend(day d)
{
  return is_in(d, day::sat, day::sun);
}
1
ответ дан Darren Smith 15 August 2018 в 23:35
поделиться

Вы можете определить набор целых чисел, добавить к нему нужные значения, а затем использовать метод find, чтобы узнать, находится ли заданное значение в наборе

std::set<int> values;
// add the desired values to your set...
if (values.find(target) != values.end())
    ...
2
ответ дан dasblinkenlight 15 August 2018 в 23:35
поделиться
  • 1
    Это интересный способ делать вещи ... Я попробую, спасибо! – Matthew Reynolds 3 March 2013 в 04:10
  • 2
    Извините, я просто получаю массу ошибок. Как именно вы используете это? Не могли бы вы привести пример? – Matthew Reynolds 3 March 2013 в 04:13
  • 3
    lol, гений в своей простоте! @TheWalkingCactus просто использует count вместо set. – user 27 June 2014 в 21:46
  • 4
    Упрощенно использовать count - if (std::set<int>({1, 2, 3}).count(target)) { ... – Chris Dodd 4 August 2018 в 07:30
  • 5
    – underscore_d 19 September 2018 в 21:25

У меня была аналогичная проблема, и я пришел к этим решениям на 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}; 
}

Или как альтернатива без метода завершения рекурсии. Имейте в виду, что здесь порядок сравнений не определен и что это не заканчивается раньше, если найдено первое совпадение. Но код более компактен.

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}; 
}

Итак, для обоих решений код будет выглядеть так:

if (is(num).in(1,2,3)) {
  // do whatever needs to be done
}
4
ответ дан Felix Petriconi 15 August 2018 в 23:35
поделиться

Вы должны выполнить сравнение с каждым значением. Например,

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

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

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

    default:
        //do nothing.
}
4
ответ дан john.pavan 15 August 2018 в 23:35
поделиться

Вот в C ++ 11, используя std::initializer_list:

#include <algorithm>
#include <initializer_list>

template <typename T>
bool is_in(const T& v, std::initializer_list<T> lst)
{
    return std::find(std::begin(lst), std::end(lst), v) != std::end(lst);
}

с этим, вы можете сделать:

if (is_in(num, {1, 2, 3})) { DO STUFF }
20
ответ дан Nikos C. 15 August 2018 в 23:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: