Reputation: 1147
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
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
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
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
Reputation: 49
int A[]={3, 8, 87, 9};
int x;
if (std::find(A, A+4, x)==A+4) SomeStuff();
Upvotes: 3
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
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
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
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