C++ 将变量与多个值进行比较的最有效方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15181579/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 19:07:50  来源:igfitidea点击:

C++ Most efficient way to compare a variable to multiple values?

c++variablesif-statementcomparison

提问by Matt Reynolds

A few times in my program, I've had to check if a variable was one of many options. For example

在我的程序中有几次,我不得不检查变量是否是众多选项之一。例如

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

I've messed around with 'OR's, but nothing seems to be right. I've tried

我弄乱了“或”,但似乎没有什么是正确的。我试过了

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

but it does nothing. Please help! Thanks in advance.

但它什么也不做。请帮忙!提前致谢。

P.S. I need to distinguish between several groups. For example...

PS我需要区分几个组。例如...

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

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

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

采纳答案by Eric Johnson

If the values you want to check are sufficiently small, you could create a bit mask of the values that you seek and then check for that bit to be set.

如果您要检查的值足够小,您可以为您寻找的值创建一个位掩码,然后检查要设置的该位。

Suppose, you care about a couple of groups.

假设,您关心几个组。

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
}

This approach works best for values that don't exceed the natural size your CPU likes to work with. This would typically be 64 in modern times, but may vary depending upon the specifics of your environment.

这种方法最适用于不超过您的 CPU 喜欢使用的自然大小的值。在现代,这通常是 64,但可能会因环境的具体情况而异。

回答by Nikos C.

Here's a way in C++11, using std::initializer_list:

这是 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);
}

with that, you can do:

有了这个,你可以这样做:

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

It is not very efficient though when not used with built-in types. intwill work fine, but if you compare std::stringvariables for example, the produced code is just awful.

但是当不与内置类型一起使用时,它不是很有效。int会工作正常,但如果你比较std::string变量,例如,生成的代码很糟糕。

In C++17 however, you can instead use a much more efficient solution that works well with any type:

但是,在 C++17 中,您可以使用更高效的解决方案,该解决方案适用于任何类型:

template<typename First, typename ... T>
bool is_in(First &&first, T && ... t)
{
    return ((first == t) || ...);
}

// ...

// s1, s2, s3, s4 are strings.
if (is_in(s1, s2, s3, s4)) // ...

The C++11 version would be very inefficient here, while this version should produce the same code as hand-written comparisons.

C++11 版本在这里效率很低,而这个版本应该产生与手写比较相同的代码。

回答by john.pavan

You have to do the comparison with each value. E.g.

您必须对每个值进行比较。例如

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

You may also want to consider a switch and intentionally falling through cases (although I don't think it's the best solution for what you're stating).

您可能还想考虑切换并故意跳过案例(尽管我认为这不是您所说的最佳解决方案)。

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

    default:
        //do nothing.
}

回答by Felix Petriconi

I just had a similar problem and I came to these C++11 solutions:

我刚刚遇到了类似的问题,我来到了这些 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}; 
}

Or as alternative without the recursion terminating method. Be aware that here the order of comparisons is undefined and that this does not terminate early if the first match is found. But the code is more compact.

或者作为没有递归终止方法的替代方法。请注意,此处的比较顺序未定义,如果找到第一个匹配项,则不会提前终止。但是代码更紧凑。

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

So for both solutions the code would look like:

因此,对于这两种解决方案,代码如下所示:

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

回答by Darren Smith

I needed to do something similar for enums. I have a variable and wish to test it against a ranges of values.

我需要为枚举做类似的事情。我有一个变量并希望针对一系列值对其进行测试。

Here I've used a variadic template function. Note the specialisation for const char*type, so that is_in( my_str, "a", "b", "c")has the expected outcome for when my_strstores "a".

这里我使用了一个可变参数模板函数。请注意const char*type的专业化,以便is_in( my_str, "a", "b", "c")具有 when my_strstores的预期结果"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...);
}

Example usage:

用法示例:

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

bool is_weekend(day d)
{
  return is_in(d, day::sat, day::sun);
}

回答by dasblinkenlight

You can define a set of integers, add the desired values to it, and then use the find method to see if the value in question is in the set

可以定义一组整数,将需要的值加入其中,然后使用find方法查看有问题的值是否在集合中

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

回答by Ajit saigal

float n;
if (n<1) exit(0);  
if (n / 3 <= 1)  
   // within 1, 2, 3
else if (n / 3 <= 2)  
   // within 4, 5, 6  
else if (n / 3 <= 3)  
   // within 7, 8, 9