Подтвердить что ты не робот

Укоротите условие, чтобы проверить, что x не является одним из четырех чисел

Есть ли способ сократить условие для этого оператора if?

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

Я думаю о чем-то вроде этого:

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

Но я пробовал это, и он не работает. Должен ли я просто написать все это долгим путем?

4b9b3361

Ответ 1

Если вы хотите узнать, является ли целое число в заданном наборе целых чисел, используйте std::set:

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

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

Ответ 2

Просто для полноты, я предлагаю использовать переключатель:

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

Пока это довольно многословно, он оценивает только x один раз (если это выражение) и, вероятно, генерирует наиболее эффективный код любого решения.

Ответ 3

Вот мое решение с использованием шаблона variadic. Производительность во время выполнения так же эффективна, как запись вручную 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;
}

Начиная с С++ 17, реализация может быть упрощена с помощью выражений складывания:

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

Ответ 4

Как насчет этого:

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

или перегрузка 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;
}

К сожалению, в данный момент парсеры не любят иметь initializer_list в качестве аргумента операторов, поэтому невозможно избавиться от std::vector<int> во втором решение.

Ответ 5

Если вы не хотите повторять это условие снова и снова, используйте макрос.

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

Ответ 6

Если числа не являются "1,2,3,4" и вместо этого представляют собой случайное число случайных чисел, то вы можете поместить эти числа в структуру данных (например, std::vector), а затем итерации по этому массиву с использованием цикла (как предложено ниже, std:: find - готовый вариант).

Например:

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

Ответ 7

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

int x;

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

Ответ 8

Обратите внимание, что использование макросов сильно осуждается многими программистами С++, так как макросы очень мощные и могут быть расстроены, если они созданы ненадлежащим образом. Однако, если они созданы и используются должным образом и разумно, они могут стать важной экономией времени. Я не вижу другого способа получить запрошенный синтаксис и кодовое пространство на сравнение, аналогичное тому, что вы запрашиваете, без ущерба для эффективности, пространства кода или памяти, используемой вашей программой. Ваша цель состояла в том, чтобы иметь ярлык, и большинство других решений, представленных здесь, длиннее того, что вы изначально хотели сократить. Вот макросы, которые сделают это безопасно, предполагая, что вы сравниваете целое число:

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

Вот пример работы с одним из указанных выше макросов:

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

Обратите внимание, что макросы должны отображаться в заголовочном файле, который включается везде, где вам нужно их использовать. Ваш код не сможет скомпилироваться, если вы уже используете переменную с именем "unused" в своем коде в другом месте или пытаетесь использовать эти макросы для сравнения чего-то другого, кроме целого. Я уверен, что вы можете расширять макросы для обработки других типов данных, если это становится необходимым.

Порядок операций сохраняется, используя скобки вокруг всех входов, и значение сохраняется в переменной перед сравнением, чтобы предотвратить множественное выполнение кода с интенсивным использованием ЦП.