Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shorten condition to check that x is not any of four numbers

Is there any way to shorten the condition for this if statement?

int x;
if (x != 3 && x != 8 && x != 87 && x != 9){
  SomeStuff();
}

I'm thinking of something sort of like this:

if (x != 3, 8, 87, 9) {}

But I tried that and it doesn't work. Do I just have to write it all out the long way?

like image 518
Aaron Beaudoin Avatar asked Jan 13 '16 05:01

Aaron Beaudoin


4 Answers

If you want to know if an integer is in a given set of integers, then use std::set:

std::set<int> accept { 1, 4, 6, 8, 255, 42 };
int x = 1;

if (!accept.count(x))
{
    // ...
}
like image 92
Alexis Pierru Avatar answered Oct 19 '22 15:10

Alexis Pierru


Just for completeness, I'll offer up using a switch:

switch (x) {
    case 1:
    case 2:
    case 37:
    case 42:
        break;
    default:
        SomeStuff();
        break;
}

While this is pretty verbose, it only evaluates x once (if it is an expression) and probably generates the most efficient code of any solution.

like image 37
1201ProgramAlarm Avatar answered Oct 19 '22 15:10

1201ProgramAlarm


Here is my solution using variadic template. The runtime performance is as efficient as manually writing x != 3 && x != 8 && x != 87 && x != 9.

template <class T, class U>
bool not_equal(const T& t, const U& u) {
  return t != u;
}

template <class T, class U, class... Vs>
bool not_equal(const T& t, const U& u, const Vs&... vs) {
  return t != u && not_equal(t, vs...);
}

int main() {
  std::cout << not_equal( 3, 3, 8, 87, 9) << std::endl;
  std::cout << not_equal( 8, 3, 8, 87, 9) << std::endl;
  std::cout << not_equal(87, 3, 8, 87, 9) << std::endl;
  std::cout << not_equal( 9, 3, 8, 87, 9) << std::endl;
  std::cout << not_equal(10, 3, 8, 87, 9) << std::endl;
}

Since C++17, the implementation can be simplified with the help of fold expressions:

template <class T, class... Vs>
bool not_equal(const T& t, const Vs&... vs) {
  return ((t != vs) && ...);
}
like image 29
Lingxi Avatar answered Oct 19 '22 13:10

Lingxi


What about this:

#include <iostream>
#include <initializer_list>
#include <algorithm>

template <typename T>
bool in(const T t, const std::initializer_list<T> & l) {
    return std::find(l.begin(), l.end(), t) != l.end();
}

int main() {
  std::cout << !in(3, {3, 8, 87, 9}) << std::endl;
  std::cout << !in(87, {3, 8, 87, 9}) << std::endl;
  std::cout << !in(10, {3, 8, 87, 9}) << std::endl;
}

or overloading the operator!=:

template<typename T>
bool operator!=(const T t, const std::vector<T> & l) {
    return std::find(l.begin(), l.end(), t) == l.end();
}

int main() {
  std::cout << ( 3!=std::vector<int>{ 3, 8, 87, 9}) << std::endl;
  std::cout << ( 8!=std::vector<int>{ 3, 8, 87, 9}) << std::endl;
  std::cout << (10!=std::vector<int>{ 3, 8, 87, 9}) << std::endl;
}

Unfortunately at the moment parsers do not like to have initializer_list as argument of operators, so it is not possible to get rid of std::vector<int> in the second solution.

like image 14
DarioP Avatar answered Oct 19 '22 14:10

DarioP