提问人:Matt Reynolds 提问时间:3/3/2013 最后编辑:cigienMatt Reynolds 更新时间:1/15/2022 访问量:109135
将一个变量与多个值进行比较的最有效方法?
Most efficient way to compare a variable to multiple values?
问:
在我的程序中,有几次我不得不检查变量是否是众多选项之一。例如
if (num = (<1 or 2 or 3>)) { DO STUFF }
我搞砸了“OR”,但似乎没有什么是对的。我试过了
if (num == (1 || 2 || 3))
但它什么也没做。
我想方便地区分几组。例如
if (num = (1,2,3))
else if (num = (4,5,6))
else if (num = (7,8,9))
答:
您必须对每个值进行比较。例如
if (num == 1 || num == 2 || num == 3) { stuff }
您可能还想考虑转换并故意失败(尽管我认为这不是您所说的最佳解决方案)。
switch (num) {
case 1:
case 2:
case 3:
{DO STUFF}
break;
default:
//do nothing.
}
评论
switch
但是,只能比较整数或枚举器类型,因此,尽管它确实适用于此类对象,并且通常很整齐,但它很快就会发现自己是一招鲜,是汇编程序跳表时代的遗物,而不是通用解决方案(因此不适合泛型代码,这非常重要)。
您可以定义一组整数,向其添加所需的值,然后使用 find 方法查看相关值是否在集合中
std::set<int> values;
// add the desired values to your set...
if (values.find(target) != values.end())
...
评论
count
set
in()
std::set.contains()。
如果要检查的值足够小,则可以创建要查找的值的位掩码,然后检查要设置的位。
假设,您关心几个组。
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
}
此方法最适用于不超过 CPU 喜欢使用的自然大小的值。在现代,这通常是 64,但可能会因环境的具体情况而异。
评论
这是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 }
但是,当不与内置类型一起使用时,它不是很有效。 可以正常工作,但是例如,如果您比较变量,则生成的代码非常糟糕。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)) // ...
C++11 版本在这里效率非常低,而这个版本应该产生与手写比较相同的代码。
评论
is_in
bool is_in(const First& first, const T& ... t)
operator==
std::forward<First>(first)
std::forward<T>(t)
const&
我刚刚遇到了类似的问题,我得出了这些 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
}
评论
T
d_
Is
我需要为枚举做类似的事情。我有一个变量,并希望根据一系列值对其进行测试。
在这里,我使用了可变参数模板函数。请注意类型的专业化,以便对 when stores 有预期的结果。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);
}
评论
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
评论
if (num == 1 || num == 2 || num == 3)
if (num >= 1 && num <= 3)
std::find