Comparison tricks in C++

前端 未结 10 1850
礼貌的吻别
礼貌的吻别 2021-01-31 16:13

A class:

class foo{
public:
    int data;
};

Now I want to add a method to this class, to do some comparison, to see if its data is equal to on

相关标签:
10条回答
  • 2021-01-31 16:45

    The answers using std::initializer_list are fine, but I want to add one more possible solution which is exactly what you where trying with that C variadic in a type-safe and modern way: Using C++11 variadic templates:

    template<typename... NUMBERS>
    bool any_equal( const foo& f , NUMBERS&&... numbers )
    {
        auto unpacked = { numbers... };
    
        return std::find( std::begin( unpacked ) , std::end( unpacked ) , f.data ) 
               != std::end( unpacked );
    };
    

    Of course this only works if all values passed are of the same type. If not the initializer list unpacked cannot be deduced nor initialized.

    Then:

    bool equals = any_equal( f , 1,2,3,4,5 );
    

    EDIT: Here is a are_same metafunction to ensure that all the numbers passed are of the same type:

    template<typename HEAD , typename... TAIL>
    struct are_same : public and_op<std::is_same<HEAD,TAIL>::value...>
    {};
    

    Where and_op performs n-ary logical and:

    template<bool HEAD , bool... TAIL>
    struct and_op : public std::integral_constant<bool,HEAD && and_op<TAIL...>::value>
    {};
    
    template<>
    struct and_op<> : public std::true_type
    {};
    

    This makes possible to force the usage of numbers of the same type in a simple way:

    template<typename... NUMBERS>
    bool any_equal( const foo& f , NUMBERS&&... numbers )
    {
        static_assert( all_same<NUMBERS...>::value , 
                       "ERROR: You should use numbers of the same type" );
    
    
        auto unpacked = { numbers... };
    
        return std::find( std::begin( unpacked ) , std::end( unpacked ) , f.data ) 
               != std::end( unpacked );
    };
    
    0 讨论(0)
  • 2021-01-31 16:47

    If data is really an integral or enumerated type, you can use a switch:

    switch (data) {
      case 1:
      case 2:
      case 2000:
      case 6000:
      case /* whatever other values you want */:
        act_on_the_group();
        break;
      default:
        act_on_not_the_group();
        break;
    }
    
    0 讨论(0)
  • 2021-01-31 16:49

    Any optimization is going to depend on properties of the set of numbers being compared to.

    If there's a definite upper bound, you can use a std::bitset. Testing membership (that is, indexing into the bitset, which behaves like an array), is O(1), effectively a few fast instructions. This is often the best solution up to limits in the hundreds, although depending on the application millions could be practical.

    0 讨论(0)
  • If data, num1, .. num6 are between 0 and 31, then you can use

    int match = ((1<<num1) | (1<<num2) | ... | (1 << num6));
    if( ( (1 << data) & match ) != 0 ) ...
    

    If num1 to num6 are constants, the compiler will compute match at compile time.

    0 讨论(0)
提交回复
热议问题