Aaron Beaudoin
Aaron Beaudoin

Reputation: 1147

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?

Upvotes: 34

Views: 2773

Answers (8)

Lingxi
Lingxi

Reputation: 14977

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) && ...);
}

Upvotes: 29

1201ProgramAlarm
1201ProgramAlarm

Reputation: 32732

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.

Upvotes: 32

azoundria
azoundria

Reputation: 1025

Note that the use of macros is heavily frowned upon by many programmers of C++, since macros are very powerful and have the ability to be frustrating if created improperly. However, if created and used properly and intelligently they can be a major time saver. I don't see another way to get the requested syntax and code space per comparison similar to what you are requesting without compromising the efficiency, code space, or memory used by your program. Your goal was to have a shortcut, and most of the other solutions presented here are longer than what you originally wanted to shorten. Here are macros which will do so safely, assuming you are comparing an integer:

#pragma once
int unused;
#define IFNOTIN2(x, a, b) \
  if (unused = (x) && unused != (a) && unused != (b))
#define IFNOTIN3(x, a, b, c) \
  if (unused = (x) && unused != (a) && unused != (b) && unused != (c))
#define IFNOTIN4(x, a, b, c, d) \
  if (unused = (x) && unused != (a) && unused != (b) && unused != (c) && unused != (d))
#define IFNOTIN5(x, a, b, c, d, e) \
  if (unused = (x) && unused != (a) && unused != (b) && unused != (c) && unused != (d) && unused != (e))

Here is a working tested example with one of the above macros:

#include <iostream>
#include "macros.h"

int main () {
  std::cout << "Hello World\n";

  for (int i = 0; i < 100; i ++) {
    std::cout << i << ": ";
    IFNOTIN4 (i, 7, 17, 32, 87) {
      std::cout << "PASSED\n";
    } else {
      std::cout << "FAILED\n";
    }
  }
  std::cin.get();

  return 0;
}

Note that the macros should go in a header file that's included wherever you need to use them. Your code will fail to compile if you are already using a variable named 'unused' in your code elsewhere or trying to use these macros to compare something other than an integer. I'm sure you can expand the macros to handle other types of data if that becomes necessary.

Order of operations is preserved by using brackets around all inputs, and the value is saved to a variable before comparison to prevent multiple executions of CPU-intensive code.

Upvotes: 3

Joshua
Joshua

Reputation: 49

int A[]={3, 8, 87, 9};

int x;

if (std::find(A, A+4, x)==A+4) SomeStuff();

Upvotes: 3

mech
mech

Reputation: 2913

If the numbers are not "1,2,3,4" and are, instead, a random number of random integers, then you could put those numbers in a data structure (such as an std::vector), and then iterate over that array using a loop (as suggested below, std::find is a ready-made option).

For example:

#include <algorithm>

int x;
std::vector<int> checknums;
// fill the vector with your numbers to check x against

if (std::find(checknums.begin(), checknums.end(), x) != checknums.end()){
    DoStuff();
}

Upvotes: 3

DarioP
DarioP

Reputation: 5465

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.

Upvotes: 14

CroCo
CroCo

Reputation: 5741

If you don't want to repeat this condition over and over, then use macro.

#include <iostream>

#define isTRUE(x, a, b, c, d)  ( x != a && x != b && x != c && x != d ) 

int main() 
{
    int x(2);
    std::cout << isTRUE(x,3,8,87,9) << std::endl;

    if ( isTRUE(x,3,8,87,9) ){
        // SomeStuff();
    }
    return 0;
}

Upvotes: 5

Alexis Pierru
Alexis Pierru

Reputation: 342

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))
{
    // ...
}

Upvotes: 43

Related Questions