快速检查一系列枚举值的方法

时间:2010-12-09 19:22:36

标签: c++ enums

是否存在语法怪异的快速/在线方式,允许您检查枚举是否具有指定值的值?

示例:

enum fruit_and_vegetables
{
    apples,
    pears,
    tomatoes,
    cucumbers
}

int main()
{
    fruit_and_vegetables something = apples;
    if( something = {apples, pears} ) // <-- this here
        cout << "something is fruit." << endl;
    else
        cout "something is a vegetable." << endl;
    return 0;
}

谢谢!

7 个答案:

答案 0 :(得分:5)

不是我知道,但您可以做的是为枚举成员分配值2^i。例如:

enum fruit_and_vegetables
{
    apples    = (1<<0),
    pears     = (1<<1),
    tomatoes  = (1<<2),
    cucumbers = (1<<3)
    // ...
}

然后你可以用

查看
if (something & (apples | pears | tomatoes))
  std::cout << "is tasty" << std::endl;

当然,这仅限于尺寸合理的枚举(我认为最多可以包含32个元素)。

修改

如果您的值超过32(64),则必须比此更有创意。 通过几次检查,你仍然可以相当快:

enum fruit_and_vegetables {
    apples    = 1, //!
    pears,
    tomatoes,
    cucumbers,
    // ...
    grapes
}
#define FRUIT_AND_VEGETABLES 120

if (   (1<<something)     & ((1<<apples) | (1<<pears) | (1<<tomatoes))
    || (1<<(something-32) & ((1<<(apples-32)) | (1<<(pears-32)) | (1<<(tomatoes-32))))
    || ...) {
  std::cout << "my keyboard is broken, but tastes good" << std::endl;
}

但这不是一个很好的解决方案。如果你有大量的枚举,并且可以将它们分成几个类,那么我会选择Noah Roberts' answer

答案 1 :(得分:4)

if (something < tomatoes)...

答案 2 :(得分:4)

啊,这可以很容易地完成......

template <typename T>
pair<T, fruit_and_vegetables> operator||(T t, fruit_and_vegetables v) {
    return make_pair(t, v);
}

template <typename T>
bool operator==(fruit_and vegetables lhs, pair<T, fruit_and_vegetables> rhs) {
    return lhs == rhs.second || lhs == rhs.first;
}

然后可以这样使用:

if (something == (apple || pear || orange)) eat_the_yummy_fruit(something);
else feed_to_rabbit(something)

但如果执行(apple || (pear || orange))则无效。这可以很容易地修复,但我想保持代码简单。我相信这是迄今为止唯一能够扩展到大型枚举的答案......

答案 3 :(得分:1)

还有另一种方法,它扩展了@bitmask的答案:

假设您可以检查固定数量的标准。因此,您可以使用额外的LUT,而不是使用位掩码作为fruit_and_vegetables枚举的值(这将限制您的单词大小),您可以使用其他LUT:

enum fruit_and_vegetables {
    apples  = 0,
    pears,
    tomatoes,
    cucumbers
}

enum qualifs {
   is_fruit = 1,
   is_sweet = 1<<1,
   is_round = 1<<2,
   is_tasty = 1<<3
}

const qualifs qualifs_LUT[] = { // can be generated
   is_fruit | is_sweet | is_round, // apple
    ...
};

以便检查特定限定符

if (qualifs_LUT[tomato] & is_tasty) 

编辑:另一种有趣的方法。考虑(再次)@bitmask:方法。它依赖于2的幂。但素数怎么样?它们的增长速度要慢得多,所以通过为枚举值指定素数,你可以吝啬更多的值,假设产品不会溢出:

enum fruit_and_vegetables {
    apples  = 2,
    pears = 3,
    tomatoes = 5,
    cucumbers = 7
}

if ((apples * pears * tomatoes) % tomatoes == 0)
     printf("it's tasty!");

这个限制了控件集中的项目数。

答案 4 :(得分:1)

您可以编写帮助程序模板来帮助您实现所需的语法:

enum fruit_and_vegetables
{
    nothing,
    apples,
    pears,
    tomatoes,
    cucumbers
};

// helper template
typedef fruit_and_vegetables fav;
template<fav v1 = nothing, fav v2 = nothing, fav v3 = nothing, fav v4 = nothing,
  fav v5 = nothing, fav v6 = nothing, fav v7 = nothing, fav v8 = nothing>
bool check_equal( fruit_and_vegetables value )
{
    return ( value == v1 || value == v2 || value == v3 || value == v4 ||
             value == v5 || value == v6 || value == v7 || value == v8 );
}

// usage
int main()
{
    fruit_and_vegetables something = apples;
    if( check_equal<apples, pears>(something) )
        std::cout << "something is fruit." << std::endl;
    else
        std::cout << "something is a vegetable." << std::endl;

    return 0;
}

答案 5 :(得分:1)

处理更大,未分类的产品组:

enum fruit_and_vegetables
{
    apples,
    pears,
    tomatoes,
    cucumbers,
    MAX_VALUE
};

vector<bool> arguablyVegetables(MAX_VALUE, false);
arguablyVegetables[tomatoes] = true;
arguablyVegetables[cucumbers] = true;

cout << arguablyVegetables[apples] << endl;

答案 6 :(得分:1)

为什么不使用set< fruit_and_vegetables >逻辑或多个fruit_and_vegetables? 如果您在运算符constexpr和运算符||重载之前放置==, 以及参数和结果类型之前, 然后编译器将在编译时评估您的代码(没有运行时开销) 如果可能的话 ;) 可以很好地扩展到更大的a || b || c || c枚举范围,您可以根据需要将值放在括号中。

#include <set>
using std::set;

enum fruit_and_vegetables
{
    apples,
    pears,
    tomatoes,
    cucumbers
};

set< fruit_and_vegetables > operator||( fruit_and_vegetables left, fruit_and_vegetables right ) {
    set< fruit_and_vegetables > set;
    set.insert( left );
    set.insert( right );
    return set;
}

set< fruit_and_vegetables > operator||( set<fruit_and_vegetables> left, fruit_and_vegetables right ) {
    left.insert( right );
    return left;
}

set< fruit_and_vegetables > operator||( fruit_and_vegetables left, set<fruit_and_vegetables> right ) {
    right.insert( left );
    return right;
}

bool operator!=( fruit_and_vegetables lhs, set<fruit_and_vegetables> rhs ) {
    return ( rhs.find( lhs ) == rhs.end() );
}

bool operator==( fruit_and_vegetables lhs, set<fruit_and_vegetables> rhs ) {
    return !( lhs != rhs );
}

int main() {

fruit_and_vegetables fav = apples;
if ( fav == ( apples || (pears || tomatoes) ) ) cout << "match apples\n";
fav = cucumbers;
if ( fav == ( (apples || pears) || tomatoes ) ) cout << "Error! matched ghost cucumbers\n";
if ( fav != apples ) cout << "correct no match apples\n";
if ( fav == cucumbers ) cout << "default operator==(FaV, FaV) match\n";
if ( fav == ( pears || apples ) ) cout << "yummi\n";

return 0;
}