Question Raccourcir la condition pour vérifier que x ne fait pas partie de quatre chiffres


Y at-il un moyen de raccourcir la condition pour cela if déclaration?

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

Je pense à quelque chose comme ça:

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

Mais j'ai essayé ça et ça ne marche pas. Dois-je simplement écrire tout ça dans le long terme?


34
2018-01-13 05:54


origine


Réponses:


Si vous voulez savoir si un entier est dans un ensemble donné d’entiers, alors utilisez std::set:

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

if (!accept.count(x))
{
    // ...
}

43
2018-01-13 06:10



Juste pour être complet, je vais offrir en utilisant un commutateur:

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

Bien que ce soit assez verbeux, il évalue seulement x une fois (si c'est une expression) et génère probablement le code le plus efficace de toute solution.


31
2018-01-13 06:23



Voici ma solution en utilisant le modèle variadic. Les performances d'exécution sont aussi efficaces que l'écriture manuelle 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;
}

28
2018-01-13 07:35



Et ça:

#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;
}

ou surcharger le 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;
}

Malheureusement pour le moment les analyseurs n'aiment pas avoir initializer_list comme argument des opérateurs, il n'est donc pas possible de se débarrasser de std::vector<int>  dans la deuxième solution.


14
2018-01-13 12:21



Si vous ne souhaitez pas répéter cette condition à plusieurs reprises, utilisez la 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;
}

5
2018-01-13 08:54



Si les nombres ne sont pas "1,2,3,4" et sont, au lieu de cela, un nombre aléatoire d'entiers aléatoires, alors vous pourriez mettre ces nombres dans une structure de données (telle qu'un std::vector), puis parcourez ce tableau en utilisant une boucle (comme suggéré ci-dessous, std :: find est une option prête à l'emploi).

Par exemple:

#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();
}

3
2018-01-13 05:59



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

int x;

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

3
2018-01-13 07:15



Notez que l'utilisation de macros est fortement désapprouvée par de nombreux programmeurs de C ++, car les macros sont très puissantes et peuvent être frustrantes si elles sont créées de manière incorrecte. Cependant, s'ils sont créés et utilisés correctement et intelligemment, ils peuvent faire gagner beaucoup de temps. Je ne vois pas d'autre moyen d'obtenir la syntaxe et l'espace de code requis par comparaison, comme vous le demandez, sans compromettre l'efficacité, l'espace de code ou la mémoire utilisés par votre programme. Votre objectif était d'avoir un raccourci, et la plupart des autres solutions présentées ici sont plus longues que ce que vous souhaitiez initialement raccourcir. Voici les macros qui le feront en toute sécurité, en supposant que vous compariez un entier:

#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))

Voici un exemple testé avec l'une des macros ci-dessus:

#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;
}

Notez que les macros doivent être placées dans un fichier d'en-tête inclus où vous en avez besoin. Votre code ne sera pas compilé si vous utilisez déjà une variable nommée «inutilisée» dans votre code ailleurs ou si vous essayez d'utiliser ces macros pour comparer autre chose qu'un entier. Je suis sûr que vous pouvez développer les macros pour gérer d'autres types de données si cela devient nécessaire.

L'ordre des opérations est préservé en utilisant des parenthèses autour de toutes les entrées, et la valeur est enregistrée dans une variable avant la comparaison pour empêcher plusieurs exécutions de code exigeant beaucoup de ressources CPU.


3
2018-01-13 12:10