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

Mat*_*lds 12 c++ variables comparison if-statement

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

if (num = (<1 or 2 or 3>)) { DO STUFF }
Run Code Online (Sandbox Code Playgroud)

我已经把'OR'弄乱了,但似乎没有什么是正确的.我试过了

if (num == (1 || 2 || 3))
Run Code Online (Sandbox Code Playgroud)

但它什么都没做.请帮忙!提前致谢.

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

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

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

else if (num = (7,8,9))
Run Code Online (Sandbox Code Playgroud)

Nik*_* C. 31

这是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);
}
Run Code Online (Sandbox Code Playgroud)

有了它,你可以这样做:

if (is_in(num, {1, 2, 3})) { DO STUFF }
Run Code Online (Sandbox Code Playgroud)

虽然不与内置类型一起使用但效率不高.int将工作正常,但如果你比较std::string变量,例如,生成的代码是可怕的.

但是,在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)) // ...
Run Code Online (Sandbox Code Playgroud)

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

  • +1用于在C++中执行此操作的非常好的方法17.如果可以的话,我会+2,因为你在5.5年后再次回来并加上它! (4认同)
  • c ++ 17功能称为[fold expression](https://en.cppreference.com/w/cpp/language/fold) (4认同)
  • `is_in` 模板内联函数很棒!我建议使用以下签名声明它:`bool is_in(const First&amp; first, const T&amp; ... t)`。如果在您的任何类中确实有一个 `operator==`,它需要至少接收一个它的参数作为可写的右值引用,那么签名将是正确的,但函数体中的参数应该通过`std::forward&lt;First&gt;(first)` 和 `std::forward&lt;T&gt;(t)`。 (2认同)

Eri*_*son 11

如果要检查的值足够小,则可以创建所查找值的位掩码,然后检查要设置的位.

假设,你关心几个群体.

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
}
Run Code Online (Sandbox Code Playgroud)

此方法最适用于不超过CPU喜欢使用的自然大小的值.现代通常为64,但可能会根据您环境的具体情况而有所不同.


das*_*ght 6

您可以定义一组整数,向其中添加所需的值,然后使用 find 方法查看相关值是否在该集合中

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

  • 大声笑,天才的简单!@TheWalkingCactus 只需使用 `count` 代替 `set`。 (2认同)
  • @Sahsahae 我不同意。对于一次性与一小组已知值进行比较的情况,集合或任何其他动态分配的容器是浪费的,并且添加全局变量是不负责任的。对于提出的实际问题,与一组已知常量相比,使用折叠表达式的可变参数“in()”函数要优越得多。 (2认同)
  • 请注意,从 C++20 开始,有 [`std::set.contains()`](https://en.cppreference.com/w/cpp/container/set/contains)。 (2认同)

Fel*_*oni 6

我遇到了类似的问题,我来到这些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}; 
}
Run Code Online (Sandbox Code Playgroud)

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

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}; 
}
Run Code Online (Sandbox Code Playgroud)

因此,对于这两种解决方案,代码看起来像:

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


小智 5

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

if (num == 1 || num == 2 || num == 3) { stuff }
Run Code Online (Sandbox Code Playgroud)

您可能还需要考虑进行切换,并故意跳过一些案例(尽管我认为这不是您所陈述的最佳解决方案)。

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

    default:
        //do nothing.
}
Run Code Online (Sandbox Code Playgroud)

  • 嗯,不,你没有_必须_这样做。 (2认同)

Dar*_*ith 5

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

这里我使用了一个可变参数模板函数。请注意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...);
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

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

bool is_weekend(day d)
{
  return is_in(d, day::sat, day::sun);
}
Run Code Online (Sandbox Code Playgroud)