我需要编写一个条件来检查值范围内的枚举变量是否可以用E语言完成:
enum EnumVariable {a, b, d, g, f, t, k, i};
if (EnumVariable in [ a, g, t, i]) {
...
}
在C ++中有没有比问{4} {等}更好的方法?
答案 0 :(得分:28)
看来,有几个人喜欢我的评论并要求将其作为答案发布,所以:
对于整数类型,实际上可以使用switch
而不是break
- s在某些值之间。
例如,您的代码可能如下所示:
enum EnumVariable {a, b, d, g, f, t, k, i};
switch( EnumVariable )
{
case a:
case g:
case t:
case i:
// do something
break;
// handler other values
};
这将非常有效,但仅适用于整数类型,而不适用于std::string
。对于其他类型,您可以尝试使用其他一些答案的建议。
写作时间有点长,但非常非常有效,可以满足您的需求。
答案 1 :(得分:21)
在C ++ 11中,表达此内容的一种简单方法是使用brace-init语法构造一个集合,并调用std::set::count
来测试该元素是否存在:
if (std::set<EnumVariable>{a, g, t, i}.count(myVariable))
...
一个可编辑的例子:
#include <set>
enum EnumVariable {a, b, d, g, f, t, k, i};
int main()
{
EnumVariable x = t;
if (std::set<EnumVariable>{a, g, t, i}.count(x)) {
return 0;
}
return 1;
}
关于效率的注意事项:由于问题是关于“比较运算符”的,所以编写答案的目的是提供一个相当可读且简短的单表达式,不需要单独的效用函数。由于它构建了一个临时std::set
,它的效率不如switch
语句,后者由所有相关编译器编译成测试或跳转表。
答案 2 :(得分:17)
语法不一致,但您可以将std::find
与std::initializer_list
一起使用。例如,
#include <algorithm>
#include <iostream>
enum EnumVariable {a, b, d, g, f, t, k, i};
int main()
{
EnumVariable e = k;
auto vals = { a, g, t, i }; // std::initializer_list<EnumVariable>
std::cout << std::boolalpha;
std::cout << (std::find(vals.begin(), vals.end(), e) != vals.end()) << std::endl;
}
这可以很容易地包含在一个辅助函数中,该函数接受枚举值,列表并返回bool
。例如:
template <typename T>
bool is_in(T elem, std::initializer_list<T> range)
{
for (T i : range)
if (i == elem) return true;
return false;
}
用法:
int main()
{
EnumVariable ev = a;
std::cout << std::boolalpha;
std::cout << is_in(ev, {a, g, t, i}) << std::endl;
}
答案 3 :(得分:16)
这通常/通常使用枚举中的位字段来实现(显然,最多为整数类型的位数(通常为32位),这是枚举基数的默认类型):
#include <iostream>
enum EnumVariable {
a=0x0001,
b=0x0002,
d=0x0004,
g=0x0008,
f=0x0010,
t=0x0020,
k=0x0040,
i=0x0080
};
inline bool CheckMatch(EnumVariable var, EnumVariable mask) {
return (var & mask) != 0;
}
using namespace std;
int main(int argc, char **argv) {
EnumVariable mask = EnumVariable(a|g|t|i);
EnumVariable x1 = b;
EnumVariable x2 = g;
cout << "x1: " << (CheckMatch(x1, mask) ? "match" : "no-match") << endl;
cout << "x2: " << (CheckMatch(x2, mask) ? "match" : "no-match") << endl;
}
很快就可以看到:
if ( x1 & (a|g|t|i) ) {
...
}
答案 4 :(得分:10)
然而另一种方法是使用模板来指定要匹配的列表,对于您的enum
情况,可能在编译时已知(否则即使switch
方法也不适用)。这允许使用如下符号:
if (in<a, b, c, d, e, f>(x))
...
启用优化后,应该内联并产生相当于:
的内容a == x || b == x || ...
下面的实施(也是ideone)。我没有玩过多变量模板,所以欢迎提出建议。特别是,如何使其类型安全,因此{@ 1}},enum E { E1 }; enum F { F1 };
将无法编译(不会将其限制为特定的in<E1>(F1)
类型)。
enum
输出:
#include <iostream>
using namespace std;
template <int First, int... Numbers>
inline bool in_impl(int n)
{
return n == First || in_impl<Numbers...>(n);
}
template <>
inline bool in_impl<int(-1)>(int n)
{
return false;
}
template <int... Numbers>
inline bool in(int n)
{
return in_impl<Numbers..., int(-1)>(n);
}
enum E { E1, E2, E3, E4 };
int main()
{
std::cout << in<3, 5, 7, 9>(4) << '\n';
std::cout << in<3, 5, 7, 9>(5) << '\n';
std::cout << in<E2, E4>(E1) << '\n';
std::cout << in<E2, E4>(E2) << '\n';
}
答案 5 :(得分:6)
这绝对不是惯用的,可能要避免,但是你可以拥有的最接近的语法(语法)是使用named operators。命名运算符实际上对应于滥用运算符重载。
enum EnumVariable {a, b, d, g, f, t, k, i};
auto in = make_named_operator(
[](int i, std::initializer_list<EnumVariable> const& x) {
return std::find(std::begin(x), std::end(x), i) != std::end(x);
});
auto vals = { a, g, t, i };
if (g <in> vals)
{
std::cout << "It works!" << std::endl;
}
Here是Coliru的一个工作示例。
如果你使用C ++ 14和多态lambda,你可以使上面的例子更通用:
auto in = make_named_operator(
[](int i, auto const& x) {
return std::find(std::begin(x), std::end(x), i) != std::end(x);
});