web-dev-qa-db-ja.com

C ++変数を複数の値と比較する最も効率的な方法は?

プログラムで数回、変数が多くのオプションの1つであるかどうかを確認する必要がありました。例えば

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))
15
Matt Reynolds

チェックする値が十分に小さい場合は、シークする値のビットマスクを作成し、そのビットが設定されているかどうかを確認できます。

いくつかのグループを気にするとします。

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ですが、環境の詳細によって異なる場合があります。

11
Eric Johnson

std::initializer_listを使用したC++ 11での方法を次に示します。

#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バージョンはここでは非常に非効率的ですが、このバージョンは手書きの比較と同じコードを生成するはずです。

30
Nikos C.

私は同様の問題を抱えていて、これらの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
}
6
Felix Petriconi

各値との比較を行う必要があります。例えば。

if (num == 1 || num == 2 || num == 3) { stuff }

また、切り替えを検討して、ケースを意図的に回避することもできます(ただし、それがあなたが言っていることに対する最善の解決策ではないと思います)。

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

    default:
        //do nothing.
}
5
john.pavan

整数のセットを定義し、それに必要な値を追加してから、findメソッドを使用して、問題の値がセット内にあるかどうかを確認できます

std::set<int> values;
// add the desired values to your set...
if (values.find(target) != values.end())
    ...
3
dasblinkenlight

列挙型についても同様のことをする必要がありました。変数があり、値の範囲に対してテストしたいと思います。

ここでは、可変長テンプレート関数を使用しました。 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);
}
2
Darren Smith